Skip to content

Commit 037ccd9

Browse files
committed
+ <PageDecodedCursor> to decode each part of encoded cursor: https://github.com/n0099/open-tbm/blob/d37cd67974090ed3e64d1e5243b7474802a7431d/be/src/PostsQuery/CursorCodec.php#L22 for <Page(Current|Next)Button>
* require `fully supports bigint`, narrow the oldest supported Chrome version from 61 to 67 @ `browserlist` @ fe
1 parent 4e1bd59 commit 037ccd9

4 files changed

Lines changed: 65 additions & 2 deletions

File tree

fe/browserslist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# https://browsersl.ist
22
defaults
33
> 0.1% in CN
4-
fully supports es6-module and fully supports url
4+
fully supports es6-module and fully supports url and fully supports bigint

fe/src/components/page/CurrentButton.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
<div class="w-auto">
55
<div class="p-2 badge bg-light text-dark">
66
<h4 v-if="currentCursor === ''" class="mb-0">起始页</h4>
7-
<h4 v-else class="mb-0">页游标 <code class="user-select-all">{{ currentCursor }}</code></h4>
7+
<h4 v-else class="mb-0">
8+
<PageDecodedCursor :encodedCursor="currentCursor" />
9+
</h4>
810
</div>
911
</div>
1012
<div class="col align-middle"><hr /></div>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<template>
2+
<div>
3+
<span>页游标 </span>
4+
<template v-for="([cursor, decoded], index) in Object.entries(decodedCursor)" :key="cursor">
5+
<code v-tippy="tippyContent(decoded)" class="user-select-all">{{ cursor }}</code>
6+
<span v-if="Object.keys(decodedCursor).length !== index + 1" class="font-monospace text-muted">,</span>
7+
</template>
8+
</div>
9+
</template>
10+
11+
<script setup lang="ts">
12+
import 'core-js/actual/typed-array/from-base64';
13+
14+
const { encodedCursor } = defineProps<{ encodedCursor: Cursor }>();
15+
type DecodedCursorPart = Record<Cursor, { description: PostIDStr | `${PostTypeText}的排序字段值`, decoded: string | bigint }>;
16+
const tippyContent = (decoded: ObjValues<DecodedCursorPart>) =>
17+
`<div class="d-flex align-items-center">${decoded.description}:<code class="user-select-all">${decoded.decoded}</code></div>`;
18+
19+
declare global {
20+
interface Uint8ArrayConstructor {
21+
22+
// https://github.com/tc39/proposal-arraybuffer-base64
23+
// https://github.com/microsoft/TypeScript/pull/61696
24+
// eslint-disable-next-line @typescript-eslint/method-signature-style
25+
fromBase64(
26+
string: string,
27+
options?: { // https://github.com/zloirock/core-js/blob/e10fa8dca0f5cea568b48e33e65fd11b06443b52/packages/core-js/internals/uint8-from-base64.js#L73-L80
28+
alphabet?: 'base64' | 'base64url',
29+
lastChunkHandling?: 'loose' | 'strict' | 'stop-before-partial'
30+
},
31+
): Uint8Array<ArrayBuffer>
32+
}
33+
}
34+
const decodeCursor = (cursor: Cursor): DecodedCursorPart | ObjEmpty => { // https://github.com/n0099/open-tbm/blob/d37cd67974090ed3e64d1e5243b7474802a7431d/be/src/PostsQuery/CursorCodec.php#L22
35+
if (cursor === '')
36+
return {};
37+
const decodePart = (part: string) => {
38+
try { // https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript/79665302#79665302
39+
return Uint8Array.fromBase64(part, { alphabet: 'base64url' })
40+
41+
// https://stackoverflow.com/questions/24288111/why-does-32-not-result-in-0-in-javascript/79665336#79665336
42+
// https://stackoverflow.com/questions/7334832/are-addition-and-bitwise-or-the-same-in-this-case
43+
// eslint-disable-next-line no-bitwise
44+
.reduce((acc, uint8, index) => acc | (BigInt(uint8) << BigInt(index * 8)), BigInt(0));
45+
} catch (e: unknown) {
46+
if (e instanceof SyntaxError) // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64
47+
return part;
48+
49+
throw e;
50+
}
51+
};
52+
const parts = cursor.split(',');
53+
if (parts.length !== 6)
54+
throw new Error('Cursor should have six parts.');
55+
56+
return Object.assign({}, ...parts.map((part, index): DecodedCursorPart =>
57+
({ [part]: { description: index % 2 === 0 ? postID[index / 2] : `${postTypeText[(index - 1) / 2]}的排序字段值`, decoded: decodePart(part) } })));
58+
};
59+
const decodedCursor = computed(() => decodeCursor(encodedCursor));
60+
</script>

fe/src/components/page/NextButton.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
</NuxtLink>
1010
</div>
1111
<div class="col align-middle"><hr /></div>
12+
<PageDecodedCursor v-if="nextCursor !== null" :encodedCursor="nextCursor" class="text-center mt-2 mb-0" />
1213
</nav>
1314
</template>
1415

0 commit comments

Comments
 (0)