Nariman Jelveh пре 11 месеци
родитељ
комит
7006dcc31c
8 измењених фајлова са 229 додато и 201 уклоњено
  1. 2 1
      src/IPC.js
  2. 9 8
      src/UI/UIDesktop.js
  3. 3 2
      src/UI/UIWindow.js
  4. 4 186
      src/helpers.js
  5. 204 0
      src/helpers/item_icon.js
  6. 3 1
      src/helpers/open_item.js
  7. 2 1
      src/helpers/refresh_item_container.js
  8. 2 2
      src/initgui.js

+ 2 - 1
src/IPC.js

@@ -30,6 +30,7 @@ import path from "./lib/path.js";
 import UIContextMenu from './UI/UIContextMenu.js';
 import update_mouse_position from './helpers/update_mouse_position.js';
 import launch_app from './helpers/launch_app.js';
+import item_icon from './helpers/item_icon.js';
 
 /**
  * In Puter, apps are loaded in iframes and communicate with the graphical user interface (GUI), and each other, using the postMessage API.
@@ -1063,7 +1064,7 @@ window.addEventListener('message', async (event) => {
                                 immutable: res.immutable,
                                 associated_app_name: res.associated_app?.name,
                                 path: target_path,
-                                icon: await window.item_icon(res),
+                                icon: await item_icon(res),
                                 name: path.basename(target_path),
                                 uid: res.uid,
                                 size: res.size,

+ 9 - 8
src/UI/UIDesktop.js

@@ -39,6 +39,7 @@ import UIWindowTaskManager from "./UIWindowTaskManager.js"
 import truncate_filename from '../helpers/truncate_filename.js';
 import UINotification from "./UINotification.js"
 import launch_app from "../helpers/launch_app.js"
+import item_icon from "../helpers/item_icon.js"
 
 async function UIDesktop(options){
     let h = '';
@@ -135,7 +136,7 @@ async function UIDesktop(options){
                     UIWindow({
                         path: '/' + notification.fields.username,
                         title: path.basename(item_path),
-                        icon: await window.item_icon({is_dir: true, path: item_path}),
+                        icon: await item_icon({is_dir: true, path: item_path}),
                         is_dir: true,
                         app: 'explorer',
                     });
@@ -217,7 +218,7 @@ async function UIDesktop(options){
         $(`.item[data-uid='${html_encode(item.uid)}'] .item-name`).html(html_encode(truncate_filename(item.name)).replaceAll(' ', ' '));
 
         // Set new icon
-        const new_icon = (item.is_dir ? window.icons['folder.svg'] : (await window.item_icon(item)).image);
+        const new_icon = (item.is_dir ? window.icons['folder.svg'] : (await item_icon(item)).image);
         $(`.item[data-uid='${item.uid}']`).find('.item-icon-thumb').attr('src', new_icon);
         $(`.item[data-uid='${item.uid}']`).find('.item-icon-icon').attr('src', new_icon);
 
@@ -338,7 +339,7 @@ async function UIDesktop(options){
             immutable: fsentry.immutable,
             uid: fsentry.uid,
             path: fsentry.path,
-            icon: await window.item_icon(fsentry),
+            icon: await item_icon(fsentry),
             name: (dest_path === window.trash_path) ? metadata.original_name : fsentry.name,
             is_dir: fsentry.is_dir,
             size: fsentry.size,
@@ -366,7 +367,7 @@ async function UIDesktop(options){
                         immutable: false,
                         uid: dir.uid,
                         path: dir.path,
-                        icon: await window.item_icon(dir),
+                        icon: await item_icon(dir),
                         name: dir.name,
                         size: dir.size,
                         type: dir.type,
@@ -421,7 +422,7 @@ async function UIDesktop(options){
         $(`.item[data-uid='${html_encode(item.uid)}'] .item-name`).html(html_encode(truncate_filename(item.name)).replaceAll(' ', ' '));
 
         // Set new icon
-        const new_icon = (item.is_dir ? window.icons['folder.svg'] : (await window.item_icon(item)).image);
+        const new_icon = (item.is_dir ? window.icons['folder.svg'] : (await item_icon(item)).image);
         $(`.item[data-uid='${item.uid}']`).find('.item-icon-icon').attr('src', new_icon);
 
         // Set new data-name
@@ -498,7 +499,7 @@ async function UIDesktop(options){
                 'data-type': item.type,
             })
             // set new icon
-            const new_icon = (item.is_dir ? window.icons['folder.svg'] : (await window.item_icon(item)).image);
+            const new_icon = (item.is_dir ? window.icons['folder.svg'] : (await item_icon(item)).image);
             $(`.item[data-uid="${item.overwritten_uid}"]`).find('.item-icon > img').attr('src', new_icon);
             
             //sort each window
@@ -513,7 +514,7 @@ async function UIDesktop(options){
                 immutable: item.immutable,
                 associated_app_name: item.associated_app?.name,
                 path: item.path,
-                icon: await window.item_icon(item),
+                icon: await item_icon(item),
                 name: item.name,
                 size: item.size,
                 type: item.type,
@@ -1007,7 +1008,7 @@ async function UIDesktop(options){
             UIWindow({
                 path: predefined_path,
                 title: path.basename(predefined_path),
-                icon: await window.item_icon({is_dir: true, path: predefined_path}),
+                icon: await item_icon({is_dir: true, path: predefined_path}),
                 // todo
                 // uid: $(el_item).attr('data-uid'),
                 is_dir: true,

+ 3 - 2
src/UI/UIWindow.js

@@ -30,6 +30,7 @@ import UIWindowSaveAccount from './UIWindowSaveAccount.js';
 import UIWindowEmailConfirmationRequired from './UIWindowEmailConfirmationRequired.js';
 import launch_app from "../helpers/launch_app.js"
 import UIWindowShare from './UIWindowShare.js';
+import item_icon from '../helpers/item_icon.js';
 
 const el_body = document.getElementsByTagName('body')[0];
 
@@ -2343,7 +2344,7 @@ $(document).on('click', '.window-sidebar-item', async function(e){
         UIWindow({
             path: item_path,
             title: path.basename(item_path),
-            icon: await window.item_icon({is_dir: true, path: item_path}),
+            icon: await item_icon({is_dir: true, path: item_path}),
             // todo
             // uid: $(el_item).attr('data-uid'),
             is_dir: true,
@@ -2405,7 +2406,7 @@ $(document).on('contextmenu taphold', '.window-sidebar-item', function(event){
                     UIWindow({
                         path: item_path,
                         title: path.basename(item_path),
-                        icon: await window.item_icon({is_dir: true, path: item_path}),
+                        icon: await item_icon({is_dir: true, path: item_path}),
                         // todo
                         // uid: $(el_item).attr('data-uid'),
                         is_dir: true,

+ 4 - 186
src/helpers.js

@@ -18,18 +18,17 @@
  */
 
 import path from "./lib/path.js"
-import mime from "./lib/mime.js";
 import UIAlert from './UI/UIAlert.js'
 import UIItem from './UI/UIItem.js'
 import UIWindowLogin from './UI/UIWindowLogin.js';
 import UIWindowSaveAccount from './UI/UIWindowSaveAccount.js';
 import update_username_in_gui from './helpers/update_username_in_gui.js';
 import update_title_based_on_uploads from './helpers/update_title_based_on_uploads.js';
-import content_type_to_icon from './helpers/content_type_to_icon.js';
 import truncate_filename from './helpers/truncate_filename.js';
 import UIWindowProgress from './UI/UIWindowProgress.js';
 import globToRegExp from "./helpers/globToRegExp.js";
 import get_html_element_from_options from "./helpers/get_html_element_from_options.js";
+import item_icon from "./helpers/item_icon.js";
 
 window.is_auth = ()=>{
     if(localStorage.getItem("auth_token") === null || window.auth_token === null)
@@ -624,187 +623,6 @@ window.sendItemChangeEventToWatchingApps = function(item_uid, event_data){
     }
 }
 
-/**
- * Assigns an icon to a filesystem entry based on its properties such as name, type, 
- * and whether it's a directory, app, trashed, or specific file type.
- * 
- * @function item_icon
- * @global
- * @async
- * @param {Object} fsentry - A filesystem entry object. It may contain various properties 
- * like name, type, path, associated_app, thumbnail, is_dir, and metadata, depending on 
- * the type of filesystem entry.
- */
-
-window.item_icon = async (fsentry)=>{
-    // --------------------------------------------------
-    // If this file is Trashed then set the name to the original name of the file before it was trashed
-    // --------------------------------------------------
-    if(fsentry.path?.startsWith(window.trash_path + '/')){
-        if(fsentry.metadata){
-            try{
-                let metadata = JSON.parse(fsentry.metadata);
-                fsentry.name = (metadata && metadata.original_name) ? metadata.original_name : fsentry.name
-            }
-            catch(e){
-                // Ignored
-            }
-        }
-    }
-    // --------------------------------------------------
-    // thumbnail
-    // --------------------------------------------------
-    if(fsentry.thumbnail){
-        return {image: fsentry.thumbnail, type: 'thumb'};
-    }
-    // --------------------------------------------------
-    // app icon
-    // --------------------------------------------------
-    else if(fsentry.associated_app && fsentry.associated_app?.name){
-        if(fsentry.associated_app.icon)
-            return {image: fsentry.associated_app.icon, type: 'icon'};
-        else
-            return {image: window.icons['app.svg'], type: 'icon'};
-    }
-    // --------------------------------------------------
-    // Trash
-    // --------------------------------------------------
-    else if(fsentry.shortcut_to_path && fsentry.shortcut_to_path === window.trash_path){
-        // get trash image, this is needed to get the correct empty vs full trash icon
-        let trash_img = $(`.item[data-path="${html_encode(window.trash_path)}" i] .item-icon-icon`).attr('src')
-        // if trash_img is undefined that's probably because trash wasn't added anywhere, do a direct lookup to see if trash is empty or no
-        if(!trash_img){
-            let trashstat = await puter.fs.stat(window.trash_path);
-            if(trashstat.is_empty !== undefined && trashstat.is_empty === true)
-                trash_img = window.icons['trash.svg'];
-            else
-                trash_img = window.icons['trash-full.svg'];
-        }
-        return {image: trash_img, type: 'icon'};
-    }
-    // --------------------------------------------------
-    // Directories
-    // --------------------------------------------------
-    else if(fsentry.is_dir){
-        // System Directories
-        if(fsentry.path === window.docs_path)
-            return {image: window.icons['folder-documents.svg'], type: 'icon'};
-        else if (fsentry.path === window.pictures_path)
-            return { image: window.icons['folder-pictures.svg'], type: 'icon' };
-        else if (fsentry.path === window.home_path)
-            return { image: window.icons['folder-home.svg'], type: 'icon' };
-        else if (fsentry.path === window.videos_path)
-            return { image: window.icons['folder-videos.svg'], type: 'icon' };
-        else if (fsentry.path === window.desktop_path)
-            return { image: window.icons['folder-desktop.svg'], type: 'icon' };
-        else if (fsentry.path === window.public_path)
-            return { image: window.icons['folder-public.svg'], type: 'icon' };
-        // regular directories
-        else
-            return {image: window.icons['folder.svg'], type: 'icon'};
-    }
-    // --------------------------------------------------
-    // Match icon by file extension
-    // --------------------------------------------------
-    // *.doc
-    else if(fsentry.name.toLowerCase().endsWith('.doc')){
-        return {image: window.icons['file-doc.svg'], type: 'icon'};
-    }
-    // *.docx
-    else if(fsentry.name.toLowerCase().endsWith('.docx')){
-        return {image: window.icons['file-docx.svg'], type: 'icon'};
-    }
-    // *.exe
-    else if(fsentry.name.toLowerCase().endsWith('.exe')){
-        return {image: window.icons['file-exe.svg'], type: 'icon'};
-    }
-    // *.gz
-    else if(fsentry.name.toLowerCase().endsWith('.gz')){
-        return {image: window.icons['file-gzip.svg'], type: 'icon'};
-    }
-    // *.jar
-    else if(fsentry.name.toLowerCase().endsWith('.jar')){
-        return {image: window.icons['file-jar.svg'], type: 'icon'};
-    }
-    // *.java
-    else if(fsentry.name.toLowerCase().endsWith('.java')){
-        return {image: window.icons['file-java.svg'], type: 'icon'};
-    }
-    // *.jsp
-    else if(fsentry.name.toLowerCase().endsWith('.jsp')){
-        return {image: window.icons['file-jsp.svg'], type: 'icon'};
-    }
-    // *.log
-    else if(fsentry.name.toLowerCase().endsWith('.log')){
-        return {image: window.icons['file-log.svg'], type: 'icon'};
-    }
-    // *.mp3
-    else if(fsentry.name.toLowerCase().endsWith('.mp3')){
-        return {image: window.icons['file-mp3.svg'], type: 'icon'};
-    }
-    // *.rb
-    else if(fsentry.name.toLowerCase().endsWith('.rb')){
-        return {image: window.icons['file-ruby.svg'], type: 'icon'};
-    }
-    // *.rss
-    else if(fsentry.name.toLowerCase().endsWith('.rss')){
-        return {image: window.icons['file-rss.svg'], type: 'icon'};
-    }
-    // *.rtf
-    else if(fsentry.name.toLowerCase().endsWith('.rtf')){
-        return {image: window.icons['file-rtf.svg'], type: 'icon'};
-    }
-    // *.sketch
-    else if(fsentry.name.toLowerCase().endsWith('.sketch')){
-        return {image: window.icons['file-sketch.svg'], type: 'icon'};
-    }
-    // *.sql
-    else if(fsentry.name.toLowerCase().endsWith('.sql')){
-        return {image: window.icons['file-sql.svg'], type: 'icon'};
-    }
-    // *.tif
-    else if(fsentry.name.toLowerCase().endsWith('.tif')){
-        return {image: window.icons['file-tif.svg'], type: 'icon'};
-    }
-    // *.tiff
-    else if(fsentry.name.toLowerCase().endsWith('.tiff')){
-        return {image: window.icons['file-tiff.svg'], type: 'icon'};
-    }
-    // *.wav
-    else if(fsentry.name.toLowerCase().endsWith('.wav')){
-        return {image: window.icons['file-wav.svg'], type: 'icon'};
-    }
-    // *.cpp
-    else if(fsentry.name.toLowerCase().endsWith('.cpp')){
-        return {image: window.icons['file-cpp.svg'], type: 'icon'};
-    }
-    // *.pptx
-    else if(fsentry.name.toLowerCase().endsWith('.pptx')){
-        return {image: window.icons['file-pptx.svg'], type: 'icon'};
-    }
-    // *.psd
-    else if(fsentry.name.toLowerCase().endsWith('.psd')){
-        return {image: window.icons['file-psd.svg'], type: 'icon'};
-    }
-    // *.py
-    else if(fsentry.name.toLowerCase().endsWith('.py')){
-        return {image: window.icons['file-py.svg'], type: 'icon'};
-    }
-    // *.xlsx
-    else if(fsentry.name.toLowerCase().endsWith('.xlsx')){
-        return {image: window.icons['file-xlsx.svg'], type: 'icon'};
-    }
-    // --------------------------------------------------
-    // Determine icon by set or derived mime type
-    // --------------------------------------------------
-    else if(fsentry.type){
-        return {image: content_type_to_icon(fsentry.type), type: 'icon'};
-    }
-    else{
-        return {image: content_type_to_icon(mime.getType(fsentry.name)), type: 'icon'};
-    }
-}
-
 /**
  * Asynchronously checks if a save account notice should be shown to the user, and if needed, displays the notice.
  *
@@ -1605,7 +1423,7 @@ window.move_items = async function(el_items, dest_path, is_undo = false){
                     associated_app_name: fsentry.associated_app?.name,
                     uid: fsentry.uid,
                     path: fsentry.path,
-                    icon: await window.item_icon(fsentry),
+                    icon: await item_icon(fsentry),
                     name: (dest_path === window.trash_path) ? $(el_item).attr('data-name') : fsentry.name,
                     is_dir: fsentry.is_dir,
                     size: fsentry.size,
@@ -1634,7 +1452,7 @@ window.move_items = async function(el_items, dest_path, is_undo = false){
                             immutable: false,
                             uid: dir.uid,
                             path: dir.path,
-                            icon: await window.item_icon(dir),
+                            icon: await item_icon(dir),
                             name: dir.name,
                             size: dir.size,
                             type: dir.type,
@@ -2277,7 +2095,7 @@ window.rename_file = async(options, new_name, old_name, old_path, el_item, el_it
             $(el_item_name_editor).hide();
 
             // Set new icon
-            const new_icon = (options.is_dir ? window.icons['folder.svg'] : (await window.item_icon(fsentry)).image);
+            const new_icon = (options.is_dir ? window.icons['folder.svg'] : (await item_icon(fsentry)).image);
             $(el_item_icon).find('.item-icon-icon').attr('src', new_icon);
 
             // Set new `data-name`

+ 204 - 0
src/helpers/item_icon.js

@@ -0,0 +1,204 @@
+/**
+ * Copyright (C) 2024 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/>.
+ */
+
+import mime from "../lib/mime.js";
+import content_type_to_icon from './content_type_to_icon.js';
+
+/**
+ * Assigns an icon to a filesystem entry based on its properties such as name, type, 
+ * and whether it's a directory, app, trashed, or specific file type.
+ * 
+ * @function item_icon
+ * @global
+ * @async
+ * @param {Object} fsentry - A filesystem entry object. It may contain various properties 
+ * like name, type, path, associated_app, thumbnail, is_dir, and metadata, depending on 
+ * the type of filesystem entry.
+ */
+
+const item_icon = async (fsentry)=>{
+    // --------------------------------------------------
+    // If this file is Trashed then set the name to the original name of the file before it was trashed
+    // --------------------------------------------------
+    if(fsentry.path?.startsWith(window.trash_path + '/')){
+        if(fsentry.metadata){
+            try{
+                let metadata = JSON.parse(fsentry.metadata);
+                fsentry.name = (metadata && metadata.original_name) ? metadata.original_name : fsentry.name
+            }
+            catch(e){
+                // Ignored
+            }
+        }
+    }
+    // --------------------------------------------------
+    // thumbnail
+    // --------------------------------------------------
+    if(fsentry.thumbnail){
+        return {image: fsentry.thumbnail, type: 'thumb'};
+    }
+    // --------------------------------------------------
+    // app icon
+    // --------------------------------------------------
+    else if(fsentry.associated_app && fsentry.associated_app?.name){
+        if(fsentry.associated_app.icon)
+            return {image: fsentry.associated_app.icon, type: 'icon'};
+        else
+            return {image: window.icons['app.svg'], type: 'icon'};
+    }
+    // --------------------------------------------------
+    // Trash
+    // --------------------------------------------------
+    else if(fsentry.shortcut_to_path && fsentry.shortcut_to_path === window.trash_path){
+        // get trash image, this is needed to get the correct empty vs full trash icon
+        let trash_img = $(`.item[data-path="${html_encode(window.trash_path)}" i] .item-icon-icon`).attr('src')
+        // if trash_img is undefined that's probably because trash wasn't added anywhere, do a direct lookup to see if trash is empty or no
+        if(!trash_img){
+            let trashstat = await puter.fs.stat(window.trash_path);
+            if(trashstat.is_empty !== undefined && trashstat.is_empty === true)
+                trash_img = window.icons['trash.svg'];
+            else
+                trash_img = window.icons['trash-full.svg'];
+        }
+        return {image: trash_img, type: 'icon'};
+    }
+    // --------------------------------------------------
+    // Directories
+    // --------------------------------------------------
+    else if(fsentry.is_dir){
+        // System Directories
+        if(fsentry.path === window.docs_path)
+            return {image: window.icons['folder-documents.svg'], type: 'icon'};
+        else if (fsentry.path === window.pictures_path)
+            return { image: window.icons['folder-pictures.svg'], type: 'icon' };
+        else if (fsentry.path === window.home_path)
+            return { image: window.icons['folder-home.svg'], type: 'icon' };
+        else if (fsentry.path === window.videos_path)
+            return { image: window.icons['folder-videos.svg'], type: 'icon' };
+        else if (fsentry.path === window.desktop_path)
+            return { image: window.icons['folder-desktop.svg'], type: 'icon' };
+        else if (fsentry.path === window.public_path)
+            return { image: window.icons['folder-public.svg'], type: 'icon' };
+        // regular directories
+        else
+            return {image: window.icons['folder.svg'], type: 'icon'};
+    }
+    // --------------------------------------------------
+    // Match icon by file extension
+    // --------------------------------------------------
+    // *.doc
+    else if(fsentry.name.toLowerCase().endsWith('.doc')){
+        return {image: window.icons['file-doc.svg'], type: 'icon'};
+    }
+    // *.docx
+    else if(fsentry.name.toLowerCase().endsWith('.docx')){
+        return {image: window.icons['file-docx.svg'], type: 'icon'};
+    }
+    // *.exe
+    else if(fsentry.name.toLowerCase().endsWith('.exe')){
+        return {image: window.icons['file-exe.svg'], type: 'icon'};
+    }
+    // *.gz
+    else if(fsentry.name.toLowerCase().endsWith('.gz')){
+        return {image: window.icons['file-gzip.svg'], type: 'icon'};
+    }
+    // *.jar
+    else if(fsentry.name.toLowerCase().endsWith('.jar')){
+        return {image: window.icons['file-jar.svg'], type: 'icon'};
+    }
+    // *.java
+    else if(fsentry.name.toLowerCase().endsWith('.java')){
+        return {image: window.icons['file-java.svg'], type: 'icon'};
+    }
+    // *.jsp
+    else if(fsentry.name.toLowerCase().endsWith('.jsp')){
+        return {image: window.icons['file-jsp.svg'], type: 'icon'};
+    }
+    // *.log
+    else if(fsentry.name.toLowerCase().endsWith('.log')){
+        return {image: window.icons['file-log.svg'], type: 'icon'};
+    }
+    // *.mp3
+    else if(fsentry.name.toLowerCase().endsWith('.mp3')){
+        return {image: window.icons['file-mp3.svg'], type: 'icon'};
+    }
+    // *.rb
+    else if(fsentry.name.toLowerCase().endsWith('.rb')){
+        return {image: window.icons['file-ruby.svg'], type: 'icon'};
+    }
+    // *.rss
+    else if(fsentry.name.toLowerCase().endsWith('.rss')){
+        return {image: window.icons['file-rss.svg'], type: 'icon'};
+    }
+    // *.rtf
+    else if(fsentry.name.toLowerCase().endsWith('.rtf')){
+        return {image: window.icons['file-rtf.svg'], type: 'icon'};
+    }
+    // *.sketch
+    else if(fsentry.name.toLowerCase().endsWith('.sketch')){
+        return {image: window.icons['file-sketch.svg'], type: 'icon'};
+    }
+    // *.sql
+    else if(fsentry.name.toLowerCase().endsWith('.sql')){
+        return {image: window.icons['file-sql.svg'], type: 'icon'};
+    }
+    // *.tif
+    else if(fsentry.name.toLowerCase().endsWith('.tif')){
+        return {image: window.icons['file-tif.svg'], type: 'icon'};
+    }
+    // *.tiff
+    else if(fsentry.name.toLowerCase().endsWith('.tiff')){
+        return {image: window.icons['file-tiff.svg'], type: 'icon'};
+    }
+    // *.wav
+    else if(fsentry.name.toLowerCase().endsWith('.wav')){
+        return {image: window.icons['file-wav.svg'], type: 'icon'};
+    }
+    // *.cpp
+    else if(fsentry.name.toLowerCase().endsWith('.cpp')){
+        return {image: window.icons['file-cpp.svg'], type: 'icon'};
+    }
+    // *.pptx
+    else if(fsentry.name.toLowerCase().endsWith('.pptx')){
+        return {image: window.icons['file-pptx.svg'], type: 'icon'};
+    }
+    // *.psd
+    else if(fsentry.name.toLowerCase().endsWith('.psd')){
+        return {image: window.icons['file-psd.svg'], type: 'icon'};
+    }
+    // *.py
+    else if(fsentry.name.toLowerCase().endsWith('.py')){
+        return {image: window.icons['file-py.svg'], type: 'icon'};
+    }
+    // *.xlsx
+    else if(fsentry.name.toLowerCase().endsWith('.xlsx')){
+        return {image: window.icons['file-xlsx.svg'], type: 'icon'};
+    }
+    // --------------------------------------------------
+    // Determine icon by set or derived mime type
+    // --------------------------------------------------
+    else if(fsentry.type){
+        return {image: content_type_to_icon(fsentry.type), type: 'icon'};
+    }
+    else{
+        return {image: content_type_to_icon(mime.getType(fsentry.name)), type: 'icon'};
+    }
+}
+
+export default item_icon;

+ 3 - 1
src/helpers/open_item.js

@@ -16,11 +16,13 @@
  * 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/>.
  */
+
 import UIWindow from '../UI/UIWindow.js';
 import UIAlert from '../UI/UIAlert.js';
 import i18n from '../i18n/i18n.js';
 import launch_app from "./launch_app.js";
 import path from '../lib/path.js';
+import item_icon from './item_icon.js';
 
 const open_item = async function(options){
     let el_item = options.item;
@@ -154,7 +156,7 @@ const open_item = async function(options){
         UIWindow({
             path: item_path,
             title: path.basename(item_path),
-            icon: await window.item_icon({is_dir: true, path: item_path}),
+            icon: await item_icon({is_dir: true, path: item_path}),
             uid: $(el_item).attr('data-uid'),
             is_dir: is_dir,
             app: 'explorer',

+ 2 - 1
src/helpers/refresh_item_container.js

@@ -19,6 +19,7 @@
 
 import path from '../lib/path.js';
 import UIItem from '../UI/UIItem.js';
+import item_icon from './item_icon.js';
 
 const refresh_item_container = function(el_item_container, options){
     options = options || {};
@@ -177,7 +178,7 @@ const refresh_item_container = function(el_item_container, options){
                         immutable: fsentry.immutable,
                         associated_app_name: fsentry.associated_app?.name,
                         path: item_path,
-                        icon: await window.item_icon(fsentry),
+                        icon: await item_icon(fsentry),
                         name: (metadata && metadata.original_name !== undefined) ? metadata.original_name : fsentry.name,
                         is_dir: fsentry.is_dir,
                         multiselectable: !is_openFileDialog,

+ 2 - 2
src/initgui.js

@@ -44,7 +44,7 @@ import { SettingsService } from './services/SettingsService.js';
 import UIComponentWindow from './UI/UIComponentWindow.js';
 import update_mouse_position from './helpers/update_mouse_position.js';
 import { LaunchOnInitService } from './services/LaunchOnInitService.js';
-
+import item_icon from './helpers/item_icon.js';
 
 const launch_services = async function (options) {
     // === Services Data Structures ===
@@ -204,7 +204,7 @@ window.initgui = async function(options){
             UIWindow({
                 path: item_path,
                 title: path.basename(item_path),
-                icon: await window.item_icon({is_dir: true, path: item_path}),
+                icon: await item_icon({is_dir: true, path: item_path}),
                 is_dir: true,
                 app: 'explorer',
             });