Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 101 additions & 16 deletions src/gui/src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import path from "./lib/path.js"
import mime from "./lib/mime.js";
import UIAlert from './UI/UIAlert.js'
import UIPrompt from './UI/UIPrompt.js'
import UIItem from './UI/UIItem.js'
import UIWindowLogin from './UI/UIWindowLogin.js';
import UIWindowSaveAccount from './UI/UIWindowSaveAccount.js';
Expand Down Expand Up @@ -849,26 +850,110 @@ window.create_file = async(options)=>{
let content = options.content ? [options.content] : [];

// create file
try{
puter.fs.upload(new File(content, filename), dirname,
{
success: async function (data){
const created_file = $(appendto_element).find('.item[data-path="'+html_encode(dirname)+'/'+html_encode(data.name)+'"]');
if(created_file.length > 0){
window.activate_item_name_editor(created_file);
return puter.fs.upload(new File(content, filename), dirname,
{
success: async function (data){
const created_file = $(appendto_element).find('.item[data-path="'+html_encode(dirname)+'/'+html_encode(data.name)+'"]');
if(created_file.length > 0){
window.activate_item_name_editor(created_file);

// Add action to actions_history for undo ability
window.actions_history.push({
operation: 'create_file',
data: created_file
});
}
// Add action to actions_history for undo ability
window.actions_history.push({
operation: 'create_file',
data: created_file
});
}
},
error: function(err){
console.error('Error creating file:', err);
}
});
}

window.create_weblink = async function(dirname, append_to_element) {
// Prompt for URL
const url = await UIPrompt({
message: i18n('enter_url_for_web_link'),
placeholder: 'https://example.com'
});

if (!url) {
return; // User cancelled
}

// Validate URL
const validUrl = url.trim();
if (!validUrl.startsWith('http://') && !validUrl.startsWith('https://')) {
UIAlert(i18n('url_must_start_with_http'), [
{ label: i18n('ok'), value: 'ok', type: 'primary' }
]);
return;
}

// Generate filename from URL
let filename;
try {
const urlObj = new URL(validUrl);
const hostname = urlObj.hostname.replace('www.', '');
// Remove protocol and get domain
filename = hostname.split('.')[0] || 'link';
filename = filename.charAt(0).toUpperCase() + filename.slice(1) + '.weblink';
} catch (e) {
filename = 'New Link.weblink';
}

// Create file with URL as content
const urlBlob = new Blob([validUrl], { type: 'text/plain' });
await window.create_file({
dirname: dirname,
append_to_element: append_to_element,
name: filename,
content: urlBlob
});
};

// Flag to prevent duplicate weblink creation
window._creating_weblink = false;

window.create_weblink_from_url = async function(dirname, append_to_element, url) {
// Prevent duplicate creation
if (window._creating_weblink) {
return;
}

window._creating_weblink = true;

try {
// Validate URL
const validUrl = url.trim();
if (!validUrl.startsWith('http://') && !validUrl.startsWith('https://')) {
return; // Not a valid URL
}

// Generate filename from URL
let filename;
try {
const urlObj = new URL(validUrl);
const hostname = urlObj.hostname.replace('www.', '');
filename = hostname.split('.')[0] || 'link';
filename = filename.charAt(0).toUpperCase() + filename.slice(1) + '.weblink';
} catch (e) {
filename = 'New Link.weblink';
}

// Create file with URL as content
const urlBlob = new Blob([validUrl], { type: 'text/plain' });
await window.create_file({
dirname: dirname,
append_to_element: append_to_element,
name: filename,
content: urlBlob
});
}catch(err){
console.log(err);
} finally {
// Reset flag immediately after file creation completes
window._creating_weblink = false;
}
}
};

window.available_templates = async () => {
const baseRoute = `/${window.user.username}`
Expand Down
4 changes: 4 additions & 0 deletions src/gui/src/helpers/item_icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ const item_icon = async (fsentry)=>{
else if(fsentry.name.toLowerCase().endsWith('.xlsx')){
return {image: window.icons['file-xlsx.svg'], type: 'icon'};
}
// *.weblink
else if(fsentry.name.toLowerCase().endsWith('.weblink')){
return {image: window.icons['link.svg'], type: 'icon'};
}
// --------------------------------------------------
// Determine icon by set or derived mime type
// --------------------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions src/gui/src/helpers/new_context_menu_item.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ const new_context_menu_item = function(dirname, append_to_element){
});
}
},
// Web Link
{
html: i18n('web_link'),
icon: `<img src="${html_encode(window.icons['link.svg'])}" class="ctx-item-icon">`,
onClick: async function() {
await window.create_weblink(dirname, append_to_element);
}
},
];

//Show file_templates on the lower part of "New"
Expand Down
42 changes: 42 additions & 0 deletions src/gui/src/helpers/open_item.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,48 @@ const open_item = async function(options){
const associated_app_name = $(el_item).attr('data-associated_app_name');
const file_uid = $(el_item).attr('data-uid');

//----------------------------------------------------------------
// Is this a .weblink file?
//----------------------------------------------------------------
if (!is_dir && path.extname(item_path).toLowerCase() === '.weblink') {
try {
// Read the URL from the file
const fileContent = await puter.fs.read(item_path);
const url = await fileContent.text();
const trimmedUrl = url.trim();

// Validate URL
if (trimmedUrl.startsWith('http://') || trimmedUrl.startsWith('https://')) {
// Open URL in new tab with security attributes
const newWindow = window.open(trimmedUrl, '_blank');
if (!newWindow) {
UIAlert(i18n('failed_to_open_url'), [
{ label: i18n('ok'), value: 'ok', type: 'primary' }
]);
} else {
// Set opener to null for security (noopener equivalent)
try {
newWindow.opener = null;
} catch (e) {
// Some browsers may throw, ignore
}
}
return;
} else {
UIAlert(i18n('invalid_url_in_weblink'), [
{ label: i18n('ok'), value: 'ok', type: 'primary' }
]);
return;
}
} catch (err) {
console.error('Error reading weblink file:', err);
UIAlert(i18n('error_reading_weblink'), [
{ label: i18n('ok'), value: 'ok', type: 'primary' }
]);
return;
}
}

//----------------------------------------------------------------
// Is this a shortcut whose source is perma-deleted?
//----------------------------------------------------------------
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/ar.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ const ar = {
"لا يمكن إعادة تسمية هذا العنصر لأنه في سلة المهملات. لإعادة تسمية هذا العنصر، اسحبه أولاً خارج سلة المهملات.",
jpeg_image: "صورة JPEG",
keep_in_taskbar: "الاحتفاظ في شريط المهام",
web_link: "رابط ويب",
enter_url_for_web_link: "أدخل عنوان URL للرابط:",
url_must_start_with_http: "يجب أن يبدأ عنوان URL بـ http:// أو https://",
failed_to_open_url: "فشل في فتح عنوان URL. يرجى التحقق من إعدادات النوافذ المنبثقة للمتصفح.",
invalid_url_in_weblink: "عنوان URL غير صالح مخزن في ملف رابط الويب هذا.",
error_reading_weblink: "خطأ في قراءة ملف رابط الويب.",
language: "اللغة",
license: "رخصة",
lightness: "إضاءة",
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/bn.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ const bn = {
items_in_trash_cannot_be_renamed: `এই আইটেমটি নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে। এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটি ট্র্যাশ থেকে তুলে নিন।`,
jpeg_image: "জেপিইজি ইমেজ",
keep_in_taskbar: "টাস্কবারে রাখুন",
web_link: "ওয়েব লিঙ্ক",
enter_url_for_web_link: "ওয়েব লিঙ্কের জন্য URL লিখুন:",
url_must_start_with_http: "URL http:// বা https:// দিয়ে শুরু হতে হবে",
failed_to_open_url: "URL খুলতে ব্যর্থ। অনুগ্রহ করে আপনার ব্রাউজারের পপআপ সেটিংস পরীক্ষা করুন।",
invalid_url_in_weblink: "এই ওয়েব লিঙ্ক ফাইলে সংরক্ষিত অবৈধ URL।",
error_reading_weblink: "ওয়েব লিঙ্ক ফাইল পড়তে ত্রুটি।",
language: "ভাষা",
license: "লাইসেন্স",
lightness: "উজ্জ্বলতা",
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/br.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ const br = {
items_in_trash_cannot_be_renamed: `Este item não pode ser renomeado porque está na lixeira. Para renomear este item, primeiro arraste-o para fora da Lixeira.`,
jpeg_image: 'Imagem JPEG',
keep_in_taskbar: 'Manter na Barra de Tarefas',
web_link: "Link da Web",
enter_url_for_web_link: "Digite o URL para o link da web:",
url_must_start_with_http: "O URL deve começar com http:// ou https://",
failed_to_open_url: "Falha ao abrir o URL. Verifique as configurações de pop-up do seu navegador.",
invalid_url_in_weblink: "URL inválido armazenado neste arquivo de link da web.",
error_reading_weblink: "Erro ao ler o arquivo de link da web.",
language: "Idioma",
license: "Licença",
lightness: 'Luminosidade',
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/da.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ const da = {
items_in_trash_cannot_be_renamed: `Dette element kan ikke omdøbes, fordi det er i papirkurven. For at omdøbe dette element, skal du først trække det ud af papirkurven.`,
jpeg_image: 'JPEG-billede',
keep_in_taskbar: 'Behold i proceslinjen',
web_link: "Weblink",
enter_url_for_web_link: "Indtast URL'en for weblinket:",
url_must_start_with_http: "URL skal starte med http:// eller https://",
failed_to_open_url: "Kunne ikke åbne URL. Tjek din browsers popup-indstillinger.",
invalid_url_in_weblink: "Ugyldig URL gemt i denne weblinkfil.",
error_reading_weblink: "Fejl ved læsning af weblinkfilen.",
language: 'Sprog',
license: 'Licens',
lightness: 'Lysstyrke',
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ const de = {
items_in_trash_cannot_be_renamed: `Dieses Element kann nicht umbenannt werden, da es sich im Papierkorb befindet. Um dieses Element umzubenennen, ziehen Sie es zunächst aus dem Papierkorb.`,
jpeg_image: 'JPEG-Bild',
keep_in_taskbar: 'In Taskleiste behalten',
web_link: "Web-Link",
enter_url_for_web_link: "Geben Sie die URL für den Web-Link ein:",
url_must_start_with_http: "URL muss mit http:// oder https:// beginnen",
failed_to_open_url: "URL konnte nicht geöffnet werden. Bitte überprüfen Sie die Popup-Einstellungen Ihres Browsers.",
invalid_url_in_weblink: "Ungültige URL in dieser Web-Link-Datei gespeichert.",
error_reading_weblink: "Fehler beim Lesen der Web-Link-Datei.",
language: "Sprache",
license: "Lizenz",
lightness: 'Helligkeit',
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/emoji.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ const emoji = {
items_in_trash_cannot_be_renamed: `🗑️🆓❌`,
jpeg_image: '🖼️',
keep_in_taskbar: '📌📁',
web_link: "🔗",
enter_url_for_web_link: "🔗 URL:",
url_must_start_with_http: "❌ URL http:// ma ọ bụ https://",
failed_to_open_url: "❌ URL",
invalid_url_in_weblink: "❌ URL",
error_reading_weblink: "❌ 📄",
loading: '🔄',
log_in: "👤🔓",
log_into_another_account_anyway: '👤🔄',
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ const en = {
items_in_trash_cannot_be_renamed: `This item can't be renamed because it's in the trash. To rename this item, first drag it out of the Trash.`,
jpeg_image: 'JPEG image',
keep_in_taskbar: 'Keep in Taskbar',
web_link: "Web Link",
enter_url_for_web_link: "Enter the URL for the web link:",
url_must_start_with_http: "URL must start with http:// or https://",
failed_to_open_url: "Failed to open URL. Please check your browser's popup settings.",
invalid_url_in_weblink: "Invalid URL stored in this web link file.",
error_reading_weblink: "Error reading web link file.",
language: "Language",
license: "License",
lightness: 'Lightness',
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ const es = {
items_in_trash_cannot_be_renamed: `Este elemento no se puede renombrar porque está en la papelera. Para cambiar el nombre de este archivo, primero extráelo fuera de la misma.`,
jpeg_image: 'Imagen JPEG',
keep_in_taskbar: 'Mantener en la barra de tareas',
web_link: "Enlace Web",
enter_url_for_web_link: "Ingrese la URL para el enlace web:",
url_must_start_with_http: "La URL debe comenzar con http:// o https://",
failed_to_open_url: "No se pudo abrir la URL. Por favor verifique la configuración de ventanas emergentes de su navegador.",
invalid_url_in_weblink: "URL inválida almacenada en este archivo de enlace web.",
error_reading_weblink: "Error al leer el archivo de enlace web.",
language: 'Lenguage',
license: 'Licencia',
lightness: 'Claridad',
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/fa.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ const fa = {
items_in_trash_cannot_be_renamed: `این مورد نمی تواند تغییر نام دهد زیرا در سطل زباله است. برای تغییر نام این مورد، ابتدا آن را از سطل زباله بیرون بکشید.`,
jpeg_image: "تصویر JPEG",
keep_in_taskbar: "در نوار وظایف نگه دارید",
web_link: "لینک وب",
enter_url_for_web_link: "URL را برای لینک وب وارد کنید:",
url_must_start_with_http: "URL باید با http:// یا https:// شروع شود",
failed_to_open_url: "باز کردن URL ناموفق بود. لطفاً تنظیمات پاپ‌آپ مرورگر خود را بررسی کنید.",
invalid_url_in_weblink: "URL نامعتبر ذخیره شده در این فایل لینک وب.",
error_reading_weblink: "خطا در خواندن فایل لینک وب.",
language: "زبان",
log_in: "ورود",
log_out: "خروج",
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/fi.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ const fi = {
items_in_trash_cannot_be_renamed: `Tätä kohdetta ei voi nimetä uudelleen, koska se on roskakorissa. Jos haluat nimetä kohteen uudelleen, palauta se ensin roskakorista.`,
jpeg_image: "JPEG-kuva",
keep_in_taskbar: "Pidä tehtäväpalkissa",
web_link: "Verkkolinkki",
enter_url_for_web_link: "Syötä verkkolinkin URL:",
url_must_start_with_http: "URL:n on alettava http:// tai https://",
failed_to_open_url: "URL:n avaaminen epäonnistui. Tarkista selaimen ponnahdusikkuna-asetukset.",
invalid_url_in_weblink: "Virheellinen URL tallennettuna tähän verkkolinkkitiedostoon.",
error_reading_weblink: "Virhe verkkolinkkitiedostoa luettaessa.",
language: "Kieli",
license: "Lisenssi",
lightness: "Valoisuus",
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ const fr = {
items_in_trash_cannot_be_renamed: `Cet élément ne peut pas être renommé car il se trouve dans la corbeille. Pour renommer cet élément, faites-le d'abord glisser hors de la corbeille.`,
jpeg_image: 'Image JPEG',
keep_in_taskbar: 'Garder dans la barre des tâches',
web_link: "Lien Web",
enter_url_for_web_link: "Entrez l'URL pour le lien Web :",
url_must_start_with_http: "L'URL doit commencer par http:// ou https://",
failed_to_open_url: "Impossible d'ouvrir l'URL. Veuillez vérifier les paramètres de popup de votre navigateur.",
invalid_url_in_weblink: "URL invalide stockée dans ce fichier de lien Web.",
error_reading_weblink: "Erreur lors de la lecture du fichier de lien Web.",
language: "Langue",
license: "Licence",
lightness: 'Luminosité',
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/he.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ const en = {
items_in_trash_cannot_be_renamed: `לא ניתן לשנות את שם הפריט הזה כי הוא נמצא באשפה. כדי לשנות את שם הפריט הזה, תחילה גרור אותו מחוץ לאשפה.`,
jpeg_image: "JPEG תמונת",
keep_in_taskbar: "שמירה בשורת המשימות",
web_link: "קישור אינטרנט",
enter_url_for_web_link: "הזן את כתובת ה-URL לקישור האינטרנט:",
url_must_start_with_http: "כתובת ה-URL חייבת להתחיל ב-http:// או https://",
failed_to_open_url: "לא ניתן לפתוח את כתובת ה-URL. אנא בדוק את הגדרות החלונות הקופצים בדפדפן שלך.",
invalid_url_in_weblink: "כתובת URL לא תקינה שמורה בקובץ קישור האינטרנט הזה.",
error_reading_weblink: "שגיאה בקריאת קובץ קישור האינטרנט.",
language: "שפה",
license: "רישיון",
lightness: "בהירות",
Expand Down
6 changes: 6 additions & 0 deletions src/gui/src/i18n/translations/hi.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ const hi = {
items_in_trash_cannot_be_renamed: "इस वस्तु का नाम नहीं बदला जा सकता क्योंकि यह कूड़ेदान में है। इस वस्तु का नाम बदलने के लिए, पहले इसे ट्रैश से बाहर खींचें।",
jpeg_image: 'जेपीईजी छवि',
keep_in_taskbar: 'टास्कबार में रखें',
web_link: "वेब लिंक",
enter_url_for_web_link: "वेब लिंक के लिए URL दर्ज करें:",
url_must_start_with_http: "URL http:// या https:// से शुरू होना चाहिए",
failed_to_open_url: "URL खोलने में विफल। कृपया अपने ब्राउज़र की पॉपअप सेटिंग्स जांचें।",
invalid_url_in_weblink: "इस वेब लिंक फ़ाइल में संग्रहीत अमान्य URL।",
error_reading_weblink: "वेब लिंक फ़ाइल पढ़ने में त्रुटि।",
language: "भाषा",
license: "लाइसेंस",
lightness: 'चमक',
Expand Down
Loading