Popup Interface Architecture
The popup serves as the primary user interface for the image extraction extension. When activated, it dispatches a collection event to the content script running on the active tab. Once the content script finishes aggregating the image URLs, it transfers the data array back to the popup for rendering and interaction. The core functionalities provided by the popup include:
- Displaying the natural dimensions (width and height) of discovered images.
- Filtering the results based on specific image size thresholds.
- Toggling the visibility of images sourced from
<img>tags, CSS backgrounds, or custom HTML attributes. - Extracting image URLs based on user-defined custom attribute rules.
- Triggering the download process for selected images.
Messaging Pipeline Between Popup and Content Script
The popup maintains a structured object to categorize the incoming image data:
const imageStore = {
customAttr: [], // Images from custom attributes
background: [], // CSS background images
standard: [] // Standard <img> tag sources
};
To initiate the extraction, the popup queries the currently active tab and dispatches a message payload containing the action type and any custom attribute configurations.
async function dispatchCollectionRequest(mode, attributeRules) {
const [currentTab] = await chrome.tabs.query({ active: true, currentWindow: true });
const payload = { mode, attributeRules };
chrome.tabs.sendMessage(currentTab.id, payload, (result) => {
if (mode === 'all') {
clearStore('customAttr');
clearStore('background');
clearStore('standard');
loadDimensions(imageStore.customAttr, result.customAttr);
loadDimensions(imageStore.background, result.background);
loadDimensions(imageStore.standard, result.standard);
} else if (mode === 'custom') {
clearStore('customAttr');
loadDimensions(imageStore.customAttr, result.customAttr);
}
});
}
On the receiving end, the content script listens for these messages. If the mode is all, it aggregates all image types; if the mode is custom, it solely retrieves custom attribute images. The Set object is utilized during the resposne construction to eliminate duplicate URLs within the same category.
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
const activeRules = request.attributeRules
? [...defaultRules, ...request.attributeRules.split(',')]
: [...defaultRules];
if (request.mode === 'all') {
sendResponse({
customAttr: [...new Set(extractCustomAttrUrls(activeRules))],
background: [...new Set(extractBackgroundUrls())],
standard: [...new Set(extractStandardImgUrls())]
});
} else if (request.mode === 'custom') {
sendResponse({
customAttr: [...new Set(extractCustomAttrUrls(activeRules))]
});
}
});
Debounced Custom Attribute Fetching
When the user modifies the custom attribute input field, the extension should avoid spamming the content script with messages. A debounce mechanism ensures the request is only sent after the user stops typing for a specified duration.
let debounceTimer = null;
function triggerCustomAttrFetch(rules) {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
dispatchCollectionRequest('custom', rules);
}, 400);
}
Resolving Natural Image Dimensions
To display the original dimensions of the extracted images, the popup dynamically creates hidden Image objects. Once the image data loads, the natural width and height are calculated and stored alongside the source URL.
function loadDimensions(storeArray, urls) {
urls.forEach(url => resolveNaturalSize(storeArray, url));
}
function resolveNaturalSize(storeArray, url) {
const imgElement = new Image();
imgElement.src = url;
imgElement.onload = () => {
storeArray.push({
source: url,
naturalWidth: imgElement.naturalWidth,
naturalHeight: imgElement.naturalHeight
});
};
}
Saving Images Locally
The download functionality relies on the Chrome Downloads API. While iterating through a selection to trigger multiple downloads is technically possible, it rapidly spawns numerous system save dialogs, resulting in a poor user experience. Consequently, the implementation focuses on individual downloads.
function saveToLocal(sourceUrl) {
chrome.downloads.download({ url: sourceUrl }, (downloadId) => {
console.log(`Download initiated with ID: ${downloadId}`);
});
}