commit 7766f4c5bc91391465f01a5aeab67e7ea11d062d Author: Kebo Date: Sat Jun 21 16:51:02 2025 -0500 initial commit - everything works!! diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..557268e Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..5e2ea05 --- /dev/null +++ b/README.md @@ -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. +``` \ No newline at end of file diff --git a/content.js b/content.js new file mode 100644 index 0000000..5a258c6 --- /dev/null +++ b/content.js @@ -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; \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..701cc71 --- /dev/null +++ b/manifest.json @@ -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" + ] +} diff --git a/moffsoft_64.png b/moffsoft_64.png new file mode 100644 index 0000000..01f4701 Binary files /dev/null and b/moffsoft_64.png differ diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..fd19828 --- /dev/null +++ b/popup.html @@ -0,0 +1,59 @@ + + + + +

new sharefeed entry

+

Required fields are in bold with a red asterisk. *

+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+

+
+ + + + \ No newline at end of file diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..6b504d9 --- /dev/null +++ b/popup.js @@ -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); +}); +