`;
html += '
';
html += ``;
html += ``;
@@ -1171,10 +1171,98 @@ export const queueMethods = {
: this.renderDownloadHistoryHtml(history);
html += '
';
+ const currentPanel = this.queueList.querySelector?.(`.mr-downloads-panel[data-downloads-view="${activeSubTab}"]`);
+ if (currentPanel && typeof document !== 'undefined') {
+ const template = document.createElement('template');
+ template.innerHTML = html;
+ const nextPanel = template.content.firstElementChild;
+ if (nextPanel) {
+ this.patchDownloadsPanelElement(currentPanel, nextPanel);
+ this.wireDownloadsPanelControls();
+ return;
+ }
+ }
+
this.queueList.innerHTML = html;
this.wireDownloadsPanelControls();
},
+ patchDownloadsPanelElement(currentElement, nextElement) {
+ const syncAttributes = (current, next) => {
+ const nextAttributeNames = new Set(Array.from(next.attributes || [], attribute => attribute.name));
+ for (const attribute of Array.from(next.attributes || [])) {
+ if (current.getAttribute(attribute.name) !== attribute.value) {
+ current.setAttribute(attribute.name, attribute.value);
+ }
+ }
+ for (const attribute of Array.from(current.attributes || [])) {
+ if (!nextAttributeNames.has(attribute.name)) {
+ current.removeAttribute(attribute.name);
+ }
+ }
+ };
+ const getNodeKey = (node) => {
+ if (node?.nodeType !== 1) return '';
+ return node.getAttribute?.('data-download-id') || '';
+ };
+ const canPatchNode = (current, next) => {
+ if (!current || current.nodeType !== next.nodeType) return false;
+ if (current.nodeType !== 1) return true;
+ if (current.tagName !== next.tagName) return false;
+ if ((current.getAttribute('class') || '') !== (next.getAttribute('class') || '')) return false;
+ const currentKey = getNodeKey(current);
+ const nextKey = getNodeKey(next);
+ return !currentKey && !nextKey ? true : currentKey === nextKey;
+ };
+ const patchNode = (current, next) => {
+ if (!canPatchNode(current, next)) {
+ const replacement = next.cloneNode(true);
+ current.replaceWith(replacement);
+ return replacement;
+ }
+ if (current.nodeType !== 1) {
+ if (current.nodeValue !== next.nodeValue) current.nodeValue = next.nodeValue;
+ return current;
+ }
+
+ syncAttributes(current, next);
+ patchChildren(current, next);
+ return current;
+ };
+ const patchChildren = (current, next) => {
+ const nextChildren = Array.from(next.childNodes || []);
+ let cursor = current.firstChild;
+
+ for (const nextChild of nextChildren) {
+ const nextKey = getNodeKey(nextChild);
+ let currentChild = cursor;
+ if (nextKey) {
+ currentChild = Array.from(current.childNodes || []).find(child => getNodeKey(child) === nextKey) || null;
+ if (currentChild && currentChild !== cursor) {
+ current.insertBefore(currentChild, cursor);
+ }
+ }
+
+ if (!currentChild) {
+ current.appendChild(nextChild.cloneNode(true));
+ cursor = null;
+ continue;
+ }
+
+ const patchedChild = patchNode(currentChild, nextChild);
+ cursor = patchedChild.nextSibling;
+ }
+
+ while (cursor) {
+ const nextSibling = cursor.nextSibling;
+ cursor.remove();
+ cursor = nextSibling;
+ }
+ };
+
+ patchNode(currentElement, nextElement);
+ },
+
wireDownloadsPanelControls() {
const bindInstantAction = (button, handler) => {
if (!button || button._hasListener) return;
@@ -1285,7 +1373,7 @@ export const queueMethods = {
? this.getContextMenuAttrs(contextModel, contextTooltip)
: '';
- html += `
`;
+ html += `
`;
html += `
`;
html += `${this.escapeHtml(filename)}`;
html += `${this.escapeHtml(statusLabel)}`;