(filePath, options = {})
| 968 | |
| 969 | function dequeueNextRenderTask() { |
| 970 | pruneDisconnectedRenderTasks(); |
| 971 | if (renderQueue.length === 0) return null; |
| 972 | if (renderQueue.length === 1) return renderQueue.shift(); |
| 973 | let minIdx = 0; |
| 974 | let minP = renderQueue[0].thumbPriority ?? THUMB_PRIORITY_BACKGROUND; |
| 975 | for (let i = 1; i < renderQueue.length; i++) { |
| 976 | const p = renderQueue[i].thumbPriority ?? THUMB_PRIORITY_BACKGROUND; |
| 977 | if (p < minP) { |
| 978 | minP = p; |
| 979 | minIdx = i; |
| 980 | } |
| 981 | } |
| 982 | return renderQueue.splice(minIdx, 1)[0]; |
| 983 | } |
| 984 | // When set during scan, any thumbnail completion (scan or grid) increments progress so bar stays in sync with visible renders |
| 985 | window._scanThumbnailProgress = null; |
| 986 | let activeRenders = 0; |
| 987 | let isProcessingQueue = false; |
| 988 | |
| 989 | // Add these at the top of the file |
| 990 | let isScanCancelled = false; |
| 991 | let isRenderCancelled = false; |
| 992 | let isBackgrounded = false; |
| 993 | |
| 994 | // Add these at the top with other global variables |
| 995 | let RENDER_DELAY = 200; // Increase delay between renders to 200ms |
| 996 | let autoStartedRendering = false; |
| 997 | let thumbnailCache = new Map(); |
| 998 | let sharedRenderer = null; |
| 999 | let renderContext = null; |
| 1000 | |
| 1001 | // Inverted filter state - tracks which filters are inverted (NOT equal instead of equal) |
| 1002 | let invertedFilters = window.invertedFilters || { |
| 1003 | tag: false, |
| 1004 | designer: false, |
| 1005 | license: false, |
| 1006 | parentModel: false, |
| 1007 | search: false |
| 1008 | }; |
| 1009 | // Ensure search flag exists if window.invertedFilters was created earlier without it |
| 1010 | if (invertedFilters.search === undefined) { |
| 1011 | invertedFilters.search = false; |
| 1012 | } |
| 1013 | // Expose inverted filters globally so search.js can read the state (keep the same object reference) |
| 1014 | window.invertedFilters = invertedFilters; |
| 1015 | |
| 1016 | // Define loadModel function at top level so it's available immediately (before DOMContentLoaded) |
| 1017 | // Helper function to parse zip path format |
| 1018 | function parseZipPath(filePath) { |
| 1019 | if (filePath.includes('::')) { |
| 1020 | const [zipPath, entryPath] = filePath.split('::'); |
| 1021 | return { zipPath, entryPath, isZipEntry: true }; |
| 1022 | } |
| 1023 | return { zipPath: filePath, entryPath: null, isZipEntry: false }; |
| 1024 | } |
| 1025 | |
| 1026 | // Helper function to get model color based on settings |
| 1027 | function getModelColor() { |
no test coverage detected