From 08bdf44b7c833726e0a2378b979dd08e5ae20b10 Mon Sep 17 00:00:00 2001 From: alan <67932758+alan16742@users.noreply.github.com> Date: Thu, 31 Oct 2024 11:53:25 +0800 Subject: [PATCH 1/4] fix: numeric sort --- back-end-cf/index.js | 5 +---- front-end/index.html | 31 +++++++++++++++---------------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/back-end-cf/index.js b/back-end-cf/index.js index ed2f26ea..9b68b2be 100644 --- a/back-end-cf/index.js +++ b/back-end-cf/index.js @@ -230,9 +230,6 @@ async function fetchFiles(path, passwd, skipToken, orderby) { : undefined; const children = pageRes.value; - if (orderby) { - orderby = orderby.replace('lastModifiedDateTime', 'time'); - } return JSON.stringify({ parent, skipToken, @@ -241,7 +238,7 @@ async function fetchFiles(path, passwd, skipToken, orderby) { .map((file) => ({ name: file.name, size: file.size, - time: file.lastModifiedDateTime, + lastModifiedDateTime: file.lastModifiedDateTime, url: file['@microsoft.graph.downloadUrl'], })) .filter((file) => file.name !== PASSWD_FILENAME), diff --git a/front-end/index.html b/front-end/index.html index 226707a3..0d555527 100644 --- a/front-end/index.html +++ b/front-end/index.html @@ -14,6 +14,7 @@ content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport" /> + - a[sortField] < b[sortField] ? -1 : 1 - ); + const files = page.files.sort(function(a, b) { + return a[sortField].toString().localeCompare(b[sortField].toString(), undefined, { + numeric: true, + sensitivity: 'base', + }); + }); if (page.orderby.includes('desc')) { files.reverse(); } @@ -886,7 +885,7 @@ .content.cloneNode(true); fileWrapper.querySelector('i').className = `zmdi zmdi-${type}`; fileWrapper.querySelector('.name').innerText = name; - fileWrapper.querySelector('.time').innerText = formatDate(time); + fileWrapper.querySelector('.lastModifiedDateTime').innerText = formatDate(time); [ fileWrapper.querySelector('.size .value').innerText, fileWrapper.querySelector('.size .unit').innerText, @@ -924,7 +923,7 @@ null, file.url ? 'file' : 'folder', file.name, - file.time, + file.lastModifiedDateTime, file.size, parent + '/' + file.name, file.url @@ -2144,7 +2143,7 @@ ) { delete payload['orderby']; } else if (orderby) { - payload.orderby = orderby.replace('time', 'lastModifiedDateTime'); + payload.orderby = orderby; } return JSON.stringify(payload); }, @@ -2188,7 +2187,7 @@
- +
@@ -2234,7 +2233,7 @@ ITEMS
-
+
TIME
From ffd09fe804c7273a50843a0b4882242346c6a81a Mon Sep 17 00:00:00 2001 From: alan <67932758+alan16742@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:12:49 +0800 Subject: [PATCH 2/4] fix: sort logical error --- front-end/index.html | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/front-end/index.html b/front-end/index.html index 0d555527..4adf0004 100644 --- a/front-end/index.html +++ b/front-end/index.html @@ -1848,11 +1848,15 @@ .className.includes('up') ? 'desc' : 'asc'; + const noNeedSort = + window.GLOBAL_CONFIG.IS_BUSINESS && + sortField !== 'name' && + loadedPages.skipToken; + if (noNeedSort) { + return; + } loadedPages.orderby = `${sortField} ${sortOrder}`; - const noSortRequest = - (window.GLOBAL_CONFIG.IS_BUSINESS && sortField !== 'name') || - !loadedPages.skipToken; - if (noSortRequest) { + if (!loadedPages.skipToken) { renderFileList(loadedPages); return; } From 14efedebcd4f5cef35cdb03b263b50d3540608db Mon Sep 17 00:00:00 2001 From: LOGI <18008498+vcheckzen@users.noreply.github.com> Date: Sat, 2 Nov 2024 04:10:00 +0800 Subject: [PATCH 3/4] Update index.html --- front-end/index.html | 133 ++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 57 deletions(-) diff --git a/front-end/index.html b/front-end/index.html index 4adf0004..b6470088 100644 --- a/front-end/index.html +++ b/front-end/index.html @@ -14,7 +14,7 @@ content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport" /> - + { date = new Date(date); const addZero = (num) => `${num}`.padStart(2, '0'); @@ -885,7 +869,8 @@ .content.cloneNode(true); fileWrapper.querySelector('i').className = `zmdi zmdi-${type}`; fileWrapper.querySelector('.name').innerText = name; - fileWrapper.querySelector('.lastModifiedDateTime').innerText = formatDate(time); + fileWrapper.querySelector('.lastModifiedDateTime').innerText = + formatDate(time); [ fileWrapper.querySelector('.size .value').innerText, fileWrapper.querySelector('.size .unit').innerText, @@ -900,6 +885,7 @@ }; const children = []; + const parent = page.parent === window.api.root ? '' : page.parent; page.files.forEach((file) => { // Only load readme not all .md files for performance reason. if (file.name.toLowerCase() === 'readme.md') { @@ -917,9 +903,8 @@ switchRightDisplay('upload'); }; } else { - const parent = page.parent === window.api.root ? '' : page.parent; - children.push( - createFileWrapper.bind( + if (!file.toFragment) { + file.toFragment = createFileWrapper.bind( null, file.url ? 'file' : 'folder', file.name, @@ -927,15 +912,15 @@ file.size, parent + '/' + file.name, file.url - ) - ); + ); + } + children.push(file); } }); - const listContainer = document.getElementById('file-list'); - if (!pageRef.lazyRenderStat) { - pageRef.lazyRenderStat = { pageSize: 200 }; - const stat = pageRef.lazyRenderStat; + if (!page.lazyRenderStat) { + page.lazyRenderStat = { pageSize: 200 }; + const stat = page.lazyRenderStat; stat.observer = new IntersectionObserver((entries) => { if (Date.now() - stat.lastRenderedTs <= 500 /* 0.5s */) { return; @@ -944,8 +929,12 @@ entries.forEach((entry) => { if (entry.isIntersecting) { stat.lastRenderedTs = Date.now(); - if (pageRef.skipToken) { - loadNextPage(pageRef); + // Do not load next page before all the data loaded being rendered. + if ( + stat.renderedItems >= stat.children.length && + page.skipToken + ) { + loadNextPage(page); } else { renderItems(); } @@ -954,34 +943,59 @@ }); }); } - const stat = pageRef.lazyRenderStat; + const stat = page.lazyRenderStat; + stat.children = children; + if (page.compare && !page.skipToken && !fromLoadNextPage) { + // All data loaded before this call, sort them all. + stat.children.sort(page.compare); + } if (!fromLoadNextPage) { + // Rendering from start, sort all loaded data for business version even if there is data unloaded. stat.renderedItems = 0; + if ( + page.compare && + page.skipToken && + window.GLOBAL_CONFIG.IS_BUSINESS + ) { + stat.children.sort(page.compare); + } } - stat.children = children; - renderItems(); + renderItems(fromLoadNextPage); - function renderItems() { + // The arg is necessary, or it will always be the value captured at the first time. + function renderItems(fromLoadNextPage) { const startIndex = stat.renderedItems; stat.renderedItems += stat.pageSize; stat.renderedItems = Math.min( stat.renderedItems, stat.children.length ); + const toBeRendered = stat.children.slice( + startIndex, + stat.renderedItems + ); + if ( + page.compare && + window.GLOBAL_CONFIG.IS_BUSINESS && + fromLoadNextPage + ) { + // Sort the new loaded slice for business version. + toBeRendered.sort(page.compare); + } + const fragment = document.createDocumentFragment(); fragment.append( - ...stat.children - .slice(startIndex, stat.renderedItems) - .map((create) => create()) + ...toBeRendered.map(({ toFragment }) => toFragment()) ); + const listContainer = document.getElementById('file-list'); if (startIndex === 0) { listContainer.replaceChildren(fragment); } else { - stat.observer.disconnect(); listContainer.lastElementChild.style.backgroundColor = '#f1f1f1'; listContainer.appendChild(fragment); } - if (pageRef.skipToken || stat.renderedItems < stat.children.length) { + stat.observer?.disconnect(); + if (page.skipToken || stat.renderedItems < stat.children.length) { stat.observer.observe(listContainer.lastElementChild); } } @@ -1669,9 +1683,9 @@ document.querySelector('.file-upload-progress').dataset.hidden = '1'; document.querySelector('.file-upload-wrapper').dataset.hidden = '0'; } else if (display === 'list') { - const sortOrder = - window.fileCache.get(window.backForwardCache.current)?.orderby || - 'name asc'; + const sortOrder = window.fileCache.get( + window.backForwardCache.current + )?.orderby; document .querySelectorAll('.list-header .row .file > div') .forEach((field) => { @@ -1838,6 +1852,15 @@ }); } + /** + * 1. 不对左侧目录树排序,仅对右侧文件列表排序。 + * 2. 若页面已加载完毕,前端对缓存拷贝整体排序。 + * 3. 若页面未加载完毕: + * A. 个人版完全依赖 API 序,前端不排序。 + * B. 商业版完全抛弃 API 序: + * a. 从头渲染列表时(打开新文件夹或点击排序按钮),前端对已加载数据的拷贝整体排序,向下滑动时,保证已加载数据显示完再加载新页,确保新页数据渲染到已加载数据后面。 + * b. 加载出新页时,前端对新页拷贝单独排序,保证新页数据渲染到已加载数据之后。 + */ function sortList(clickedElem) { const loadedPages = window.fileCache.get( window.backForwardCache.current @@ -1848,15 +1871,17 @@ .className.includes('up') ? 'desc' : 'asc'; - const noNeedSort = - window.GLOBAL_CONFIG.IS_BUSINESS && - sortField !== 'name' && - loadedPages.skipToken; - if (noNeedSort) { - return; - } + const reverseFactor = sortOrder === 'asc' ? 1 : -1; loadedPages.orderby = `${sortField} ${sortOrder}`; - if (!loadedPages.skipToken) { + loadedPages.compare = (a, b) => + reverseFactor * + a[sortField] + .toString() + .localeCompare(b[sortField].toString(), undefined, { + numeric: true, + sensitivity: 'base', + }); + if (!loadedPages.skipToken || window.GLOBAL_CONFIG.IS_BUSINESS) { renderFileList(loadedPages); return; } @@ -2140,14 +2165,8 @@ method: 'POST', formatPayload: (path, passwd, kvs) => { const payload = { path, passwd, ...kvs }; - const orderby = payload.orderby; - if ( - window.GLOBAL_CONFIG.IS_BUSINESS && - !orderby?.startsWith('name') - ) { + if (window.GLOBAL_CONFIG.IS_BUSINESS) { delete payload['orderby']; - } else if (orderby) { - payload.orderby = orderby; } return JSON.stringify(payload); }, From 72c3cd5ed41a9331fee79c84764879a6b119d453 Mon Sep 17 00:00:00 2001 From: LOGI <18008498+vcheckzen@users.noreply.github.com> Date: Sat, 2 Nov 2024 04:10:48 +0800 Subject: [PATCH 4/4] Update index.js --- back-end-cf/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/back-end-cf/index.js b/back-end-cf/index.js index 9b68b2be..d2c204c1 100644 --- a/back-end-cf/index.js +++ b/back-end-cf/index.js @@ -1,11 +1,9 @@ /** - * IS_CN: 如果为世纪互联版本,请将 0 改为 1 * EXPOSE_PATH:暴露路径,如全盘展示请留空,否则按 '/媒体/音乐' 的格式填写 * ONEDRIVE_REFRESHTOKEN: refresh_token * PASSWD_FILENAME: 密码文件名 * PROTECTED_LAYERS: EXPOSE_PATH 目录密码防护层数,防止猜测目录,默认 -1 为关闭,类似 '/Applications' 需要保护填写为 2(保护 EXPOSE_PATH 及其一级子目录),开启需在 EXPORSE_PATH 目录的 PASSWORD_FILENAME 文件中填写密码 */ -const IS_CN = 0; const EXPOSE_PATH = ''; const ONEDRIVE_REFRESHTOKEN = ''; const PASSWD_FILENAME = '.password';