FileSaver.js - saveAs does not display Save As dialog in Chrome extension

122 Views Asked by At

I am working on a Chrome extension that scrapes the menu information of a restaurant on a food delivery platform (e.g. UberEats, FoodPanda) and stores it in an Excel file as well as downloading menu images, which are then compiled into a ZIP archive to be downloaded onto the disk. However, running FileSaver.js' saveAs function for the ZIP archive does not display the Save As dialog for the location to download the file. No error was thrown despite the Save As dialog not displaying on calling saveAs.

Manifest

{
    "manifest_version": 3,
    "name": "Menu scraper",
    "description": "Scrapes menu information and downloads a zip file containing an Excel file on menu information and menu image files",
    "version": "0.1",
    "action": {
        "default_popup": "popup.html"
    },
    "background": {
        "service_worker": "content.js"
    },
    "content_scripts": [
        {
            "matches": [
                "www.foodpanda.my"
            ],
            "js": [
                "xlsx.full.min.js",
                "jszip.min.js",
                "FileSaver.min.js",
                "scraper.js",
                "export.js"
            ]
        }
    ],
    "host_permissions": [
        "www.foodpanda.my",
        "image-hosting-site.com"
    ],
    "permissions": [
        "tabs",
        "activeTab",
        "scripting",
        "contextMenus",
        "downloads",
        "storage"
    ]
}

content.js

importScripts('./xlsx.full.min.js')
importScripts("./jszip.min.js")
importScripts("./FileSaver.min.js")
importScripts("./scraper.js")
importScripts("./export.js")

chrome.contextMenus.create({
    "id": "scrape_menu",
    "title": "Save menu to Excel file",
    "contexts": ["page"]
})

chrome.contextMenus.onClicked.addListener((clickData) => {
    if (clickData.menuItemId == "scrape_menu") {
        chrome.tabs.query({'active': true, 'windowId': chrome.windows.WINDOW_ID_CURRENT},
            function(tabs){
                var tab = tabs[0]
                
                // Run scraper script then pass data to export script
                chrome.scripting.executeScript({target: { tabId: tab.id }, func: scrape_menu,
                }, function(selection) {
                    var vendor = selection[0].result
                    if (vendor) {
                        console.log(vendor)
                        export_vendor(vendor)
                    }
                });
            }
        );
    }
})

export.js

async function export_vendor(vendor) {
    // Create workbook
    var name = vendor['name']
    var dishes = vendor['dishes']
    console.log(vendor)
    console.log("Creating menu for "+name)
    var wb = XLSX.utils.book_new()
    wb.Props = {
        Title: name
    }
    // Insert menu contents
    var ws = XLSX.utils.aoa_to_sheet(dishes, { origin: 'A2', skipHeader: true });
    // Add header
    let heading = [['No.', 'Name', 'Category', 'Price', 'Description', 'Image URL']];
    XLSX.utils.sheet_add_aoa(ws, heading);
    XLSX.utils.book_append_sheet(wb, ws, name);

    // Write to Excel file
    var wbout = XLSX.write(wb, {bookType:'xlsx', type:'binary'});
    
    var zip = new JSZip();
    zip.file("Menu.xlsx", wbout, {binary: true});
    zip.file("ReadMe.txt", name)
    
    // Get images
    var img_urls = [];
    for (let dish of dishes) { img_urls.push(dish[5]); }
    
    const promises = img_urls.map(async (url) => {
        const res = await fetch(url);
        const blob = await res.blob();
        return blob;
    })
    
    const res = await Promise.all(promises)
    var img_folder = zip.folder("images")
    
    res.forEach((blob, index) => {
        var img_filename = `${index} - ${dishes[index][1]}.jpg`;
        img_folder.file(img_filename, blob);
        console.log(`Saving ${img_filename}`);
    })
    
    // Download ZIP file
    zip.generateAsync({type:"blob"})
    .then((content) => {
        console.log("Saving to ZIP file");
        saveAs(content, `${name}.zip`); // No Save As dialog?
        console.log("ZIP file created. Web scraping complete.")
    });
}

The problem applies to file types other than just the ZIP file, as using saveAs on the Excel file in the export script also resulted in the Save As dialog not displaying as well.

0

There are 0 best solutions below