Remove mods and favicons

This commit is contained in:
jelveh
2025-06-27 22:46:34 -07:00
parent 196f996435
commit aeac392a7c
7 changed files with 8 additions and 617 deletions

View File

@@ -1,240 +0,0 @@
/**
* Web Shortcuts Mod for Puter
*
* This mod adds a "Create Web Shortcut" option to the context menu
* that allows users to create .weblink files that open websites.
*/
const BaseService = require("../../../src/backend/src/services/BaseService");
class WebShortcutsService extends BaseService {
async _init() {
const svc_puterHomepage = this.services.get('puter-homepage');
svc_puterHomepage.register_script('/web-shortcuts/main.js');
}
}
// Function to extract URL from text (handles pasted URLs)
function extractURL(text) {
// Remove any warning messages that might be in the pasted content
const cleanText = text.replace(/Warning.*?(?=http)/s, '').trim();
// Try to find a URL in the text
const urlRegex = /(https?:\/\/[^\s]+)/g;
const matches = cleanText.match(urlRegex);
if (matches && matches.length > 0) {
return matches[0];
}
return text;
}
// Function to validate URL
function isValidURL(url) {
try {
new URL(url);
return true;
} catch (error) {
return false;
}
}
// Function to create a web shortcut
async function createWebShortcut(targetPath, url = null) {
try {
// If no URL provided, prompt the user
if (!url) {
let userInput = prompt('Enter or paste the URL for the web shortcut:', 'https://example.com');
if (!userInput) {
console.log('User cancelled URL input');
return;
}
url = extractURL(userInput);
}
// Ensure URL has protocol
if (!url.startsWith('http://') && !url.startsWith('https://')) {
url = 'https://' + url;
}
// Validate URL
if (!isValidURL(url)) {
console.error('Invalid URL:', url);
alert('Invalid URL. Please enter a valid URL.');
return;
}
// Get the website title (for the shortcut name)
const validUrl = new URL(url);
const siteName = validUrl.hostname;
// Get the favicon
const faviconUrl = `https://www.google.com/s2/favicons?domain=${validUrl.origin}&sz=64`;
// Create a JSON file that will store the shortcut data
const shortcutData = {
url: validUrl.href,
icon: faviconUrl,
type: 'web_shortcut'
};
// Create the shortcut file
const shortcutFileName = `${siteName}.weblink`;
// Get the target path (default to desktop if not provided)
const desktopPath = window.desktop_path || '/Desktop';
const targetDirectory = targetPath || desktopPath;
// Write the file
const result = await window.puter.fs.write(
targetDirectory + '/' + shortcutFileName,
JSON.stringify(shortcutData),
{ dedupeName: true }
);
console.log('Web shortcut created:', result);
} catch (error) {
console.error('Error creating web shortcut:', error);
alert('Error creating web shortcut: ' + error.message);
}
}
// Handle URL drops on desktop
window.addEventListener('dragover', function(e) {
// Check if we're dragging over the desktop
if (!$(e.target).closest('.desktop').length) return;
// Check if we have text/uri-list or text/plain data
if (e.dataTransfer.types.includes('text/uri-list') ||
e.dataTransfer.types.includes('text/plain')) {
e.preventDefault();
e.stopPropagation();
}
});
window.addEventListener('drop', async function(e) {
// Check if we're dropping on the desktop
if (!$(e.target).closest('.desktop').length) return;
// Check if we have text/uri-list or text/plain data
if (e.dataTransfer.types.includes('text/uri-list')) {
e.preventDefault();
e.stopPropagation();
const url = e.dataTransfer.getData('text/uri-list');
if (isValidURL(url)) {
await createWebShortcut(window.desktop_path, url);
}
} else if (e.dataTransfer.types.includes('text/plain')) {
e.preventDefault();
e.stopPropagation();
const text = e.dataTransfer.getData('text/plain');
const url = extractURL(text);
if (isValidURL(url)) {
await createWebShortcut(window.desktop_path, url);
}
}
});
// Handle URL pastes on desktop
window.addEventListener('paste', async function(e) {
// Check if we're pasting on the desktop
if (!$(e.target).closest('.desktop').length) return;
const text = e.clipboardData.getData('text/plain');
const url = extractURL(text);
if (isValidURL(url)) {
e.preventDefault();
e.stopPropagation();
await createWebShortcut(window.desktop_path, url);
}
});
// Add "Create Web Shortcut" to the desktop context menu
window.addEventListener('ctxmenu-will-open', function(e) {
const options = e.detail.options;
// Only add to desktop context menu or directory context menus
if (!options || !options.items) return;
// Check if this is a desktop or directory context menu
const isDesktopOrDirMenu = options.items.some(item =>
(item.html === 'New Folder' || item.html === i18n('new_folder')) ||
(item.html === 'Paste' || item.html === i18n('paste'))
);
if (isDesktopOrDirMenu) {
// Find the position to insert our menu item (after "New Folder")
let insertIndex = options.items.findIndex(item =>
item.html === 'New Folder' || item.html === i18n('new_folder')
);
if (insertIndex === -1) {
// If "New Folder" not found, insert at the beginning
insertIndex = 0;
} else {
// Insert after "New Folder"
insertIndex += 1;
}
// Get the target path
let targetPath;
if (options.parent_element) {
const $parentElement = $(options.parent_element);
if ($parentElement.hasClass('item-container')) {
targetPath = $parentElement.attr('data-path');
} else if ($parentElement.hasClass('item') && $parentElement.attr('data-is_dir') === '1') {
targetPath = $parentElement.attr('data-path');
}
}
// Insert our menu item
options.items.splice(insertIndex, 0, {
html: 'Create Web Shortcut',
icon: '<img src="' + window.icons['link.svg'] + '" style="width:16px; height:16px; margin-bottom: -3px;">',
onClick: function() {
createWebShortcut(targetPath);
}
});
}
});
// Add "Create Web Shortcut" to the "New" submenu in the desktop context menu
const originalUIContextMenu = window.UIContextMenu;
window.UIContextMenu = function(options) {
if (options && options.items) {
// Find the "New" submenu
const newItemIndex = options.items.findIndex(item =>
(item.html === 'New' || item.html === i18n('new')) &&
Array.isArray(item.items)
);
if (newItemIndex !== -1 && options.items[newItemIndex].items) {
// Add our item to the "New" submenu
options.items[newItemIndex].items.push({
html: 'Web Shortcut',
icon: '<img src="' + window.icons['link.svg'] + '" style="width:16px; height:16px; margin-bottom: -3px;">',
onClick: function() {
// Get the target path
let targetPath;
if (options.parent_element) {
const $parentElement = $(options.parent_element);
if ($parentElement.hasClass('item-container')) {
targetPath = $parentElement.attr('data-path');
} else if ($parentElement.hasClass('item') && $parentElement.attr('data-is_dir') === '1') {
targetPath = $parentElement.attr('data-path');
}
}
createWebShortcut(targetPath);
}
});
}
}
return originalUIContextMenu(options);
};
module.exports = WebShortcutsService;

View File

@@ -1,11 +0,0 @@
{
"name": "web-shortcuts",
"version": "1.0.0",
"description": "Create web shortcuts on the desktop",
"author": "Puter",
"license": "MIT",
"dependencies": ["fs", "path"],
"client": {
"scripts": ["/mods/web-shortcuts"]
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright (C) 2024-present Puter Technologies Inc.
*
* This file is part of Puter.
*
* Puter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const WebShortcutsService = require('./index');
module.exports = {
name: 'web-shortcuts',
version: '1.0.0',
description: 'Create web shortcuts on the desktop',
author: 'Puter',
license: 'MIT',
dependencies: ['fs', 'path'],
init: async (puter) => {
const service = new WebShortcutsService(puter);
await service.init();
return service;
},
routes: {
'/mods/web-shortcuts': {
GET: (req, res) => {
res.sendFile(__dirname + '/public/main.js');
}
}
}
};

View File

@@ -1,11 +0,0 @@
{
"name": "web-shortcuts",
"version": "1.0.0",
"description": "Create web shortcuts on the desktop",
"author": "Puter",
"license": "MIT",
"dependencies": {
"fs": "*",
"path": "*"
}
}

View File

@@ -1,197 +0,0 @@
// Web Shortcuts Mod
(function() {
console.log('[Web Shortcuts] Mod initializing...');
// URL validation helper
function isValidURL(str) {
const pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain
'((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4)
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment
return !!pattern.test(str);
}
// Extract URL from text
function extractURL(text) {
// Clean the text
text = text.trim();
// If it's already a valid URL, return it
if (isValidURL(text)) {
return text;
}
// Try to extract a URL
const urlRegex = /(https?:\/\/[^\s]+)/g;
const matches = text.match(urlRegex);
return matches ? matches[0] : null;
}
// Create web shortcut
async function createWebShortcut(url, name = null) {
console.log('[Web Shortcuts] Creating shortcut with URL:', url);
try {
if (!url) {
url = await window.puter.prompt('Enter URL:');
if (!url) return;
}
// Add https:// if no protocol specified
if (!url.startsWith('http://') && !url.startsWith('https://')) {
url = 'https://' + url;
}
if (!isValidURL(url)) {
console.log('[Web Shortcuts] Invalid URL:', url);
window.puter.alert('Invalid URL');
return;
}
// Get domain/hostname and build favicon link
const { hostname } = new URL(url);
const favicon = `https://www.google.com/s2/favicons?domain=${hostname}&sz=64`;
// Use hostname as default name if none provided
if (!name) {
name = await window.puter.prompt('Enter shortcut name:', hostname);
if (!name) return;
}
console.log('[Web Shortcuts] Creating shortcut:', { url, name, favicon });
const shortcutData = {
url: url,
favicon: favicon,
created: new Date().toISOString(),
type: 'link'
};
// Build the path for storing the shortcut
const filePath = `${window.desktop_path}/${name}.weblink`;
// Write the file
const file = await window.puter.fs.write(
filePath,
JSON.stringify(shortcutData),
{
type: 'link',
icon: favicon
}
);
console.log('[Web Shortcuts] File created:', file);
// Create the UI icon on the desktop
window.UIItem({
appendTo: $('.desktop.item-container'),
'data-type': 'link',
uid: file.uid,
path: filePath,
icon: favicon,
name: name,
is_dir: false,
metadata: JSON.stringify(shortcutData)
});
window.puter.notify('Web shortcut created successfully');
} catch (error) {
console.error('[Web Shortcuts] Error creating shortcut:', error);
window.puter.alert('Error creating web shortcut: ' + (error.message || 'Please check the URL and try again'));
}
}
// Add context menu items
window.addEventListener('DOMContentLoaded', () => {
console.log('[Web Shortcuts] DOM Content Loaded');
// Get desktop element
const el_desktop = document.querySelector('.desktop');
console.log('[Web Shortcuts] Desktop element found:', !!el_desktop);
if (!el_desktop) return;
// Handle paste events
el_desktop.addEventListener('paste', (e) => {
console.log('[Web Shortcuts] Paste event on desktop:', e.target === el_desktop);
if (e.target !== el_desktop) return;
const text = e.clipboardData.getData('text');
if (isValidURL(text)) {
e.preventDefault();
createWebShortcut(text);
}
});
// Handle drop events
el_desktop.addEventListener('drop', (e) => {
console.log('[Web Shortcuts] Drop event on desktop:', e.target === el_desktop);
if (e.target !== el_desktop) return;
e.preventDefault();
const url = e.dataTransfer.getData('text/uri-list') || e.dataTransfer.getData('text/plain');
if (url && isValidURL(url)) {
createWebShortcut(url);
}
});
// Listen for context menu opening
window.addEventListener('ctxmenu-will-open', (e) => {
console.log('[Web Shortcuts] Context menu will open:', e.detail);
const options = e.detail.options;
// Only modify desktop context menu
if (!options || !options.items) {
console.log('[Web Shortcuts] No menu options found');
return;
}
// Check if this is a desktop context menu
const isDesktopMenu = options.items.some(item =>
(item.html === 'New Folder' || item.html === window.i18n('new_folder')) ||
(item.html === 'Paste' || item.html === window.i18n('paste'))
);
console.log('[Web Shortcuts] Is desktop menu:', isDesktopMenu);
if (isDesktopMenu) {
// Find the position to insert our menu item (after "New")
const newIndex = options.items.findIndex(item =>
item.html === 'New' || item.html === window.i18n('new')
);
console.log('[Web Shortcuts] New menu index:', newIndex);
// Insert our menu item after "New" and before the next divider
if (newIndex !== -1) {
let insertIndex = newIndex + 1;
// Find the next divider
while (insertIndex < options.items.length && options.items[insertIndex] !== '-') {
insertIndex++;
}
console.log('[Web Shortcuts] Inserting at index:', insertIndex);
// Insert our item before the divider
options.items.splice(insertIndex, 0, {
html: 'Create Web Shortcut',
icon: '<img src="' + window.icons['link.svg'] + '" style="width:16px; height:16px; margin-bottom: -3px;">',
onClick: () => createWebShortcut()
});
console.log('[Web Shortcuts] Menu items after insertion:', options.items);
}
}
});
// Add right-click handler to desktop
el_desktop.addEventListener('contextmenu', (e) => {
console.log('[Web Shortcuts] Context menu event on desktop:', e.target === el_desktop);
// Only handle right-clicks directly on the desktop, not on items
if (e.target !== el_desktop) return;
// The rest of the context menu handling will be done by the ctxmenu-will-open event
});
console.log('[Web Shortcuts] All event listeners attached');
});
console.log('[Web Shortcuts] Mod initialization complete');
})();

View File

@@ -196,58 +196,6 @@ const item_icon = async (fsentry)=>{
}
// *.weblink
else if(fsentry.name.toLowerCase().endsWith('.weblink')){
let faviconUrl = null;
// First try to get icon from data attribute
if (fsentry.icon) {
faviconUrl = fsentry.icon;
}
// Then try metadata
else if (fsentry.metadata) {
try {
const metadata = JSON.parse(fsentry.metadata);
if (metadata && metadata.faviconUrl) {
faviconUrl = metadata.faviconUrl;
} else if (metadata && metadata.url) {
// If we have the URL but no favicon, generate the Google favicon URL
const urlObj = new URL(metadata.url);
faviconUrl = `https://www.google.com/s2/favicons?domain=${urlObj.hostname}&sz=64`;
}
} catch (e) {
console.error("Error parsing weblink metadata:", e);
}
}
// Finally try content
else if (fsentry.content) {
try {
const content = JSON.parse(fsentry.content);
if (content && content.faviconUrl) {
faviconUrl = content.faviconUrl;
} else if (content && content.url) {
// If we have the URL but no favicon, generate the Google favicon URL
const urlObj = new URL(content.url);
faviconUrl = `https://www.google.com/s2/favicons?domain=${urlObj.hostname}&sz=64`;
}
} catch (e) {
console.error("Error parsing weblink content:", e);
}
}
// If we found a favicon URL, use it
if (faviconUrl) {
return {
image: faviconUrl,
type: 'icon',
onerror: function() {
// If favicon fails to load, switch to default icon
const $icons = $(`img[data-icon="${faviconUrl}"]`);
$icons.attr('src', window.icons['link.svg']);
return window.icons['link.svg'];
}
};
}
// Fallback to default link icon
return {image: window.icons['link.svg'], type: 'icon'};
}
// --------------------------------------------------

View File

@@ -307,10 +307,10 @@ const new_context_menu_item = function(dirname, append_to_element){
});
if (url) {
// Extract domain for naming and favicon
try {
const urlObj = new URL(url);
const domain = urlObj.hostname;
// Extract domain for naming
try {
const urlObj = new URL(url);
const domain = urlObj.hostname;
// Extract a simple name from the domain (e.g., "google" from "google.com")
let siteName = domain.replace(/^www\./, '');
@@ -325,21 +325,9 @@ const new_context_menu_item = function(dirname, append_to_element){
let linkName = siteName;
let fileName = linkName + '.weblink';
// Get favicon URL from Google favicon service
let faviconUrl = `https://www.google.com/s2/favicons?domain=${domain}&sz=64`;
// Check if we have a cached favicon
if (window.favicon_cache[domain]) {
faviconUrl = window.favicon_cache[domain];
}
// Store in favicon cache
window.favicon_cache[domain] = faviconUrl;
// Store the URL and favicon in a comprehensive JSON object
// Store the URL in a simple JSON object
const weblink_content = JSON.stringify({
url: url,
faviconUrl: faviconUrl,
type: 'weblink',
domain: domain,
created: Date.now(),
@@ -347,22 +335,20 @@ const new_context_menu_item = function(dirname, append_to_element){
version: '2.0',
metadata: {
originalUrl: url,
originalFaviconUrl: faviconUrl,
linkName: linkName,
simpleName: siteName
}
});
// Create the file with favicon
// Create the file with standard link icon
const item = await window.create_file({
dirname: dirname,
append_to_element: append_to_element,
name: fileName,
content: weblink_content,
icon: faviconUrl,
icon: window.icons['link.svg'],
type: 'weblink',
metadata: JSON.stringify({
faviconUrl: faviconUrl,
url: url,
domain: domain,
timestamp: Date.now(),
@@ -370,7 +356,7 @@ const new_context_menu_item = function(dirname, append_to_element){
}),
html_attributes: {
'data-weblink': 'true',
'data-icon': faviconUrl,
'data-icon': window.icons['link.svg'],
'data-url': url,
'data-domain': domain,
'data-display-name': linkName,
@@ -379,49 +365,6 @@ const new_context_menu_item = function(dirname, append_to_element){
force_refresh: true,
class: 'weblink-item'
});
// Apply icon using our consolidated function
if (item) {
applyWeblinkIcon(item, faviconUrl, url);
// Ensure the item is visible in the container
const container = append_to_element || document.querySelector('.desktop, .explorer-container.active, .files-container.active');
if (container) {
// Force a refresh of the container
await refresh_item_container(dirname);
// Hide the extension in the displayed name
const $item = $(item);
const $nameElement = $item.find('.item-name');
if ($nameElement.length > 0) {
// Store the original name for reference
$nameElement.attr('data-full-name', fileName);
$nameElement.attr('data-display-name', linkName);
// Set the text directly (no extension)
$nameElement.text(linkName);
}
// If this is the desktop, trigger a desktop refresh
if (container.classList.contains('desktop')) {
if (typeof window.refresh_desktop === 'function') {
window.refresh_desktop();
} else if (typeof window.refresh_desktop_items === 'function') {
window.refresh_desktop_items();
}
}
// Trigger a custom event to ensure icon is properly applied
const event = new CustomEvent('weblink-created', {
detail: {
item: item,
url: url,
faviconUrl: faviconUrl
}
});
document.dispatchEvent(event);
}
}
} catch (error) {
console.error("Error creating web link:", error);
UIAlert("Error creating web link: " + error.message);