initial commit - everything works!!

This commit is contained in:
Kebo 2025-06-21 16:51:02 -05:00
commit 7766f4c5bc
7 changed files with 219 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

31
README.md Normal file
View file

@ -0,0 +1,31 @@
# Sharefeed Entry Tool
A silly little Chrome extension I created to more easily create Sharefeed entries while I am on the web.
When you click the moffsoft icon, a popup will show up with all of the possible fields, with some or even most of them auto-populated with
data from the page. Clicking "generate" will generate the JSON code in a field you can easily copy and paste from.
This is just a tool I made for myself, but if you want to use it for your own implementation of the Sharefeed... I mean....... I guess?
## Supported Sites
You can technically use this extension on *any* site, as it will always automatically fill in the URL and date accessed fields for you.
However, I've built in additional autofill support for certain websites.
- Medium: Title, author, and date published fields are autofilled from the handy [`NewsArticle` JSON-LD schema](https://schema.org/NewsArticle)
included on every page.
## Wait, what is this even for?
I have a page on my site called the [sharefeed](https://eleboog.com/sharefeed) where I share links to things I think are interesting.
To make the implementation of this slightly easier on myself, I've stored all the links in a JSON file where each entry is a single object
in the following format:
```typescript
url: string // The URL of the linked page.
title: string // The title of the entry. Usually analogous to the title of the linked page or article.
author: string? // The author of the linked page.
publishedDate: Date? // The date in which the linked page was **originally published**.
accessedDate: Date // The date in which the linked page was **accessed by me** (i.e. the date of this entry itself).
note: string // A message to be attached to this link, usually detailing why I decided to share it.
```

15
content.js Normal file
View file

@ -0,0 +1,15 @@
//==================================================
// sharefeed entry tool - by kebokyo
// content.js - examines the content of the page
// for data autofill
// created june 21, 2025
//==================================================
let entry = {
title: ""
};
// if schema.org JSON-LD is present, read that data
return entry;

15
manifest.json Normal file
View file

@ -0,0 +1,15 @@
{
"name": "Sharefeed Entry Tool",
"description": "Creates a sharefeed entry based on the current webpage.",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_icon": "moffsoft_64.png",
"default_popup": "popup.html"
},
"permissions": [
"storage",
"activeTab",
"scripting"
]
}

BIN
moffsoft_64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

59
popup.html Normal file
View file

@ -0,0 +1,59 @@
<html>
<style>
body {
max-width: fit-content;
}
form {
display: flexbox;
}
input, textarea {
margin-bottom: 0.75rem;
}
input[type="submit"] {
margin-bottom: 0.5rem;
}
hr {
margin-bottom: 0.5rem;
}
.red {
color: red;
}
textarea[readonly] {
background-color: #eeeeee;
margin-bottom: 0px;
}
#error {
color: red;
}
</style>
<body>
<script src="popup.js"></script>
<h1>new sharefeed entry</h1>
<p>Required fields are in <b>bold</b> with a red asterisk. <span class="red">*</span></p>
<form id="sharefeed">
<label for="url"><b>url</b><span class="red">*</span></label>
<input id="url" name="url" type="url" size="50"/>
<br/>
<label for="title"><b>title</b><span class="red">*</span></label>
<input id="title" name="title" type="text" size="50"/>
<br/>
<label for="author">author</label>
<input id="author" name="author" type="text"/>
<br/>
<label for="publishedDate">date published</label>
<input id="publishedDate" name="publishedDate" type="datetime-local" step="1"/>
<br/>
<label for="accessedDate"><b>date accessed</b><span class="red">*</span></label>
<input id="accessedDate" name="accessedDate" type="datetime-local" step="1"/>
<br/>
<label for="note"><b>note</b><span class="red">*</span></label>
<textarea form="sharefeed" id="note" name="note" rows="4" cols="50"></textarea>
<br/>
<button id="submit" name="submit" type="submit">generate</button>
</form>
<p id="error"></p>
<hr/>
<label for="generated">generated JSON</label>
<textarea id="generated" name="generated" rows="8" cols="50" readonly aria-readonly></textarea>
</body>
</html>

99
popup.js Normal file
View file

@ -0,0 +1,99 @@
function parsePage() {
let entry = {
url: window.location.href,
title: "",
publishedDate: ""
};
// fix the URL's of certain websites
if (entry.url.startsWith('https://freedium.cfd/')) { // extract original article link from freedium url
entry.url = entry.url.replace('https://freedium.cfd/', '');
}
// if schema.org JSON-LD is present, read that data
const jsonLDElem = document.querySelector('script[type="application/ld+json"]');
if (jsonLDElem) {
const jsonLDObj = JSON.parse(jsonLDElem.textContent);
if (jsonLDObj['@type'] == 'NewsArticle') {
entry.publishedDate = jsonLDObj.datePublished?.slice(0, 19) ?? "";
entry.author = jsonLDObj.author?.name ?? ""
entry.title = jsonLDObj.headline ?? ""
}
}
return entry;
}
// thanks stack overflow: https://stackoverflow.com/questions/12413243/javascript-date-format-like-iso-but-local
function dateToISOLikeButLocal(date) {
const offsetMs = date.getTimezoneOffset() * 60 * 1000;
const msLocal = date.getTime() - offsetMs;
const dateLocal = new Date(msLocal);
const iso = dateLocal.toISOString();
const isoLocal = iso.slice(0, 19);
return isoLocal;
}
function fillForm(entry) {
const curDate = new Date();
document.getElementById('url').value = entry.url;
document.getElementById('title').value = entry.title ?? "";
document.getElementById('author').value = entry.author ?? "";
document.getElementById('publishedDate').value = entry.publishedDate ?? "";
document.getElementById('accessedDate').value = dateToISOLikeButLocal(curDate);
}
function runContentScript(tabId) {
chrome.scripting.executeScript({
target: { tabId: tabId},
func: parsePage,
}).then((injectionResults) => {
fillForm(injectionResults[0].result);
});
}
function generateJSON(event) {
event.preventDefault();
const urlField = document.getElementById('url');
const titleField = document.getElementById('title');
const authorField = document.getElementById('author');
const publishedDateField = document.getElementById('publishedDate');
const accessedDateField = document.getElementById('accessedDate');
const noteField = document.getElementById('note');
const errorElem = document.getElementById('error');
const JSONElem = document.getElementById('generated');
// first, make sure all of our required fields are in place
if ((urlField.value == null || urlField.value == "") ||
(titleField.value == null || titleField.value == "") ||
(accessedDateField.value == null || accessedDateField.value == "") ||
(noteField.value == null || noteField.value == "")) {
errorElem.textContent = "ERROR: Missing required field."
return;
}
errorElem.textContent = ""
JSONElem.value = `{
"url": "${urlField.value}",
"title": "${titleField.value}",
"author": "${authorField.value}",
"publishedDate": "${publishedDateField.value.replace('T', ' ')}",
"accessedDate": "${accessedDateField.value.replace('T', ' ')}",
"note": "${noteField.value}",\n},`
}
window.addEventListener('DOMContentLoaded', () => {
chrome.tabs.query({
active: true,
currentWindow: true
}, tabs => {
runContentScript(tabs[0].id);
});
const form = document.getElementById('sharefeed')
form.addEventListener('submit', generateJSON);
});