diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 3348807..b0963c1 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -33,7 +33,7 @@ const logout = async () => {
// Check for click events on the navbar burger icon
const toggleBurger = () => {
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
- isBurgerActive.value = !isBurgerActive
+ isBurgerActive.value = !isBurgerActive.value
}
diff --git a/frontend/src/components/DateTimePicker.vue b/frontend/src/components/DateTimePicker.vue
new file mode 100644
index 0000000..be4df76
--- /dev/null
+++ b/frontend/src/components/DateTimePicker.vue
@@ -0,0 +1,678 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ cell.value ?? NBSP }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ cell.value ?? NBSP }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/MessageBox.vue b/frontend/src/components/MessageBox.vue
index 1a2d0dd..2a1e3fa 100644
--- a/frontend/src/components/MessageBox.vue
+++ b/frontend/src/components/MessageBox.vue
@@ -5,14 +5,24 @@ const isVisible = ref(false);
const title = ref("");
const content = ref("");
+const emit = defineEmits<{
+ (e: 'closed', isOk: boolean): void
+}>()
+
const show = (_content: string, _title?: string) => {
title.value = _title ?? "Notification";
content.value = _content;
isVisible.value = true;
}
-const hide = () => {
+const close = () => {
isVisible.value = false;
+ emit('closed', false);
+}
+
+const ok = () => {
+ isVisible.value = false;
+ emit('closed', true);
}
defineExpose({
@@ -26,13 +36,13 @@ defineExpose({
diff --git a/frontend/src/components/collection/OwnedItem.vue b/frontend/src/components/collection/OwnedItem.vue
index 364572e..bdff1a6 100644
--- a/frontend/src/components/collection/OwnedItem.vue
+++ b/frontend/src/components/collection/OwnedItem.vue
@@ -35,7 +35,7 @@ const deleteItem = () => {
}
const updateItem = () => {
- let new_name = editingName.value;
+ const new_name = editingName.value;
editingName.value = "";
isEditing.value = false;
emit('update', props.uuid, new_name);
diff --git a/frontend/src/utils/datetime.ts b/frontend/src/utils/datetime.ts
index a01aae1..2fee3c3 100644
--- a/frontend/src/utils/datetime.ts
+++ b/frontend/src/utils/datetime.ts
@@ -62,7 +62,7 @@ type LoopStopRule = InfinityStopRule | DatetimeStopRule | TimesStopRule;
export function resolveLoopRules4UI(strl: string): [LoopRule, LoopStopRule] | undefined {
if (strl == '') return undefined;
- let sp = strl.split('-');
+ const sp = strl.split('-');
if (sp.length != 2) return undefined;
let loopRules: LoopRule | undefined = undefined;
let loopStopRules: LoopStopRule | undefined = undefined;
@@ -130,35 +130,35 @@ export function resolveLoopRules2Event(
Math.max(loopDateTimeEnd, eventDateTimeEnd)]
];
- let sp = fullLoopRules.split('-');
+ const sp = fullLoopRules.split('-');
if (sp.length != 2) return undefined;
- let loopRules = sp[0]!; // we don't need consider stop flag
- let result: TimeRange[] = new Array();
+ const loopRules = sp[0]!; // we don't need consider stop flag
+ const result: TimeRange[] = [];
// compute offset and duration
- let eventDateTime = new Date((eventDateTimeStart + timezoneOffset) * 60000);
+ const eventDateTime = new Date((eventDateTimeStart + timezoneOffset) * 60000);
eventDateTime.setUTCHours(0, 0, 0, 0);
- let eventOffset = eventDateTimeStart - (Math.floor(eventDateTime.getTime() / 60000) - timezoneOffset);
- let eventDuration = eventDateTimeEnd - eventDateTimeStart;
+ const eventOffset = eventDateTimeStart - (Math.floor(eventDateTime.getTime() / 60000) - timezoneOffset);
+ const eventDuration = eventDateTimeEnd - eventDateTimeStart;
- let detectDateTime = new Date(loopDateTimeStart * 60000);
+ const detectDateTime = new Date(loopDateTimeStart * 60000);
detectDateTime.setUTCHours(0, 0, 0, 0);
- let originalYear = eventDateTime.getUTCFullYear();
- let originalMonth = eventDateTime.getUTCMonth() + 1;
- let originalDay = eventDateTime.getUTCDate();
+ const originalYear = eventDateTime.getUTCFullYear();
+ const originalMonth = eventDateTime.getUTCMonth() + 1;
+ const originalDay = eventDateTime.getUTCDate();
// compute event
let match: RegExpExecArray | null;
if ((match = PRECOMPILED_LOOP_RULES.year.exec(loopRules)) !== null) {
- let isStrict = match[1]! == 'S';
- let loopSpan = parseInt(match[2]!);
+ const isStrict = match[1]! == 'S';
+ const loopSpan = parseInt(match[2]!);
- let yearCount = detectDateTime.getFullYear() - originalYear;
- let isSpecial = (originalMonth == 2 && originalDay == 29);
- let realLoopSpan = (isSpecial && isStrict) ? lcm(4, loopSpan) : loopSpan;
+ const yearCount = detectDateTime.getFullYear() - originalYear;
+ const isSpecial = (originalMonth == 2 && originalDay == 29);
+ const realLoopSpan = (isSpecial && isStrict) ? lcm(4, loopSpan) : loopSpan;
//let fullSpanCount = Math.floor(yearCount / realLoopSpan);
- let remainYear = yearCount % realLoopSpan;
+ const remainYear = yearCount % realLoopSpan;
//detectDateTime.setUTCFullYear(fullSpanCount + detectDateTime.getUTCFullYear(), 1, 1);
if (remainYear != 0)
detectDateTime.setUTCFullYear(realLoopSpan - remainYear + detectDateTime.getUTCFullYear(), 1 - 1, 1);
@@ -189,22 +189,22 @@ export function resolveLoopRules2Event(
}
} else if ((match = PRECOMPILED_LOOP_RULES.month.exec(loopRules)) !== null) {
- let isStrict = match[1]! == 'S';
- let loopMethod = match[2]!;
- let loopSpan = parseInt(match[3]!);
+ const isStrict = match[1]! == 'S';
+ const loopMethod = match[2]!;
+ const loopSpan = parseInt(match[3]!);
- let monthsCountValue = monthsCount(detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1) -
+ const monthsCountValue = monthsCount(detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1) -
monthsCount(originalYear, originalMonth);
//let fullSpanCount = Math.floor(monthsCountValue / loopSpan);
- let remainMonth = monthsCountValue % loopSpan;
+ const remainMonth = monthsCountValue % loopSpan;
//detectDateTime.setUTCMonth(fullSpanCount * loopSpan + detectDateTime.getUTCMonth(), 1);
detectDateTime.setUTCDate(1);
if (remainMonth != 0)
detectDateTime.setUTCMonth(loopSpan - remainMonth + detectDateTime.getUTCMonth(), 1);
while (Math.floor(detectDateTime.getTime() / 60000) + eventOffset - timezoneOffset <= loopDateTimeEnd) {
- let data = getRemanagedDayInMonth(originalYear, originalMonth, originalDay, detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1, isStrict);
+ const data = getRemanagedDayInMonth(originalYear, originalMonth, originalDay, detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1, isStrict);
let predictedDay: number | undefined = undefined;
switch (loopMethod) {
case 'A':
@@ -233,15 +233,15 @@ export function resolveLoopRules2Event(
} else if ((match = PRECOMPILED_LOOP_RULES.week.exec(loopRules)) !== null) {
- let loopSpan = parseInt(match[2]!);
- let weekOption: boolean[] = [];
+ const loopSpan = parseInt(match[2]!);
+ const weekOption: boolean[] = [];
let weekEventCount = 0
for (let i = 0; i < 7; i++) {
weekOption.push(match[1]![i] == 'T');
if (match[1]![i] == 'T') weekEventCount++;
}
- let originalWeek = dayOfWeek(originalYear, originalMonth, originalDay);
+ const originalWeek = dayOfWeek(originalYear, originalMonth, originalDay);
// try insert original event
if (!weekOption[originalWeek]) {
@@ -250,11 +250,11 @@ export function resolveLoopRules2Event(
);
}
- let daysCountValue = daysCount(detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1, detectDateTime.getDate()) -
+ const daysCountValue = daysCount(detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1, detectDateTime.getDate()) -
daysCount(originalYear, originalMonth, originalDay);
//let fullSpanCount = Math.floor(daysCountValue / (7 * loopSpan));
- let remainFullSpanCount = Math.floor((daysCountValue % (7 * loopSpan)) / 7);
- let remainDays = (daysCountValue % (7 * loopSpan)) % 7;
+ const remainFullSpanCount = Math.floor((daysCountValue % (7 * loopSpan)) / 7);
+ const remainDays = (daysCountValue % (7 * loopSpan)) % 7;
//detectDateTime.setUTCDate((7 * loopSpan * fullSpanCount) + detectDateTime.getUTCDate());
if (remainFullSpanCount != 0) {
@@ -276,12 +276,12 @@ export function resolveLoopRules2Event(
}
} else if ((match = PRECOMPILED_LOOP_RULES.day.exec(loopRules)) !== null) {
- let loopSpan = parseInt(match[1]!);
+ const loopSpan = parseInt(match[1]!);
- let daysCountValue = daysCount(detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1, detectDateTime.getUTCDate()) -
+ const daysCountValue = daysCount(detectDateTime.getUTCFullYear(), detectDateTime.getUTCMonth() + 1, detectDateTime.getUTCDate()) -
daysCount(originalYear, originalMonth, originalDay);
//let fullSpanCount = Math.floor(daysCountValue / loopSpan);
- let remainDays = daysCountValue % loopSpan;
+ const remainDays = daysCountValue % loopSpan;
//detectDateTime.setUTCDate(fullSpanCount * loopSpan + detectDateTime.getUTCDate());
if (remainDays != 0)
detectDateTime.setUTCDate(loopSpan - remainDays + detectDateTime.getUTCDate());
@@ -296,10 +296,10 @@ export function resolveLoopRules2Event(
} else return undefined;
// clamp item
- let realResult: TimeRange[] = new Array();
- for (let i of result) {
- let start = i[0];
- let end = i[1];
+ const realResult: TimeRange[] = [];
+ for (const i of result) {
+ const start = i[0];
+ const end = i[1];
if (end > clampStartDateTime && start <= loopDateTimeEnd)
realResult.push([Math.max(start, clampStartDateTime), Math.min(end, loopDateTimeEnd)]);
}
@@ -319,11 +319,11 @@ export function resolveLoopRules2Event(
export function resolveLoopRules4Text(strl: string, startDateTime: number, timezoneOffset: number): string {
if (strl == '') return "";
- let sp = strl.split('-');
+ const sp = strl.split('-');
if (sp.length != 2) return "";
let loopRules: string;
let loopStopRules: string;
- let datetimeInstance = new Date((startDateTime + timezoneOffset) * 60000)
+ const datetimeInstance = new Date((startDateTime + timezoneOffset) * 60000)
let match: RegExpExecArray | null;
if ((match = PRECOMPILED_LOOP_RULES.year.exec(sp[0]!)) !== null) {
@@ -340,7 +340,7 @@ export function resolveLoopRules4Text(strl: string, startDateTime: number, timez
else
loopRules = "宽松模式。";
- let dayInMonth = getDayInMonth(
+ const dayInMonth = getDayInMonth(
datetimeInstance.getUTCFullYear(),
datetimeInstance.getUTCMonth() + 1,
datetimeInstance.getUTCDate());
@@ -367,7 +367,7 @@ export function resolveLoopRules4Text(strl: string, startDateTime: number, timez
break;
}
} else if ((match = PRECOMPILED_LOOP_RULES.week.exec(sp[0]!)) !== null) {
- let weekOfDayCache = [];
+ const weekOfDayCache = [];
for (let i = 0; i < 7; i++) {
if (match[1]![i] == 'T')
weekOfDayCache.push(universalGetDayOfWeek(i));
@@ -414,7 +414,7 @@ function leapYearCountEx(endYear: number, includeThis: boolean, baseYear: number
}
function daysCount(year: number, month: number, day: number): number {
- let ly = leapYearCountEx(year, false, 1, true);
+ const ly = leapYearCountEx(year, false, 1, true);
let days = 365 * (year - 1);
days += ly;
@@ -432,7 +432,7 @@ function monthsCount(year: number, month: number): number {
return (year - 1) * 12 + (month - 1);
}
-function dayOfWeek(year: number, month: number, day: number): number {
+export function dayOfWeek(year: number, month: number, day: number): number {
return daysCount(year, month, day) % 7;
}
@@ -452,15 +452,15 @@ type DayInMonthInfo = [
];
function getDayInMonth(year: number, month: number, day: number): DayInMonthInfo {
- let days = MONTH_DAY_COUNT[month - 1]! + ((month == 2 && isLeapYear(year)) ? 1 : 0);
- let firstDayOfWeek = dayOfWeek(year, month, 1);
- let bilateralDayOfWeek = (firstDayOfWeek + day - 1) % 7;
+ const days = MONTH_DAY_COUNT[month - 1]! + ((month == 2 && isLeapYear(year)) ? 1 : 0);
+ const firstDayOfWeek = dayOfWeek(year, month, 1);
+ const bilateralDayOfWeek = (firstDayOfWeek + day - 1) % 7;
- let dayForwards = day;
- let dayBackwards = days - day + 1;
+ const dayForwards = day;
+ const dayBackwards = days - day + 1;
- let weeksForward = Math.floor((dayForwards - 1) / 7) + 1;
- let weeksBackwards = Math.floor((dayBackwards - 1) / 7) + 1;
+ const weeksForward = Math.floor((dayForwards - 1) / 7) + 1;
+ const weeksBackwards = Math.floor((dayBackwards - 1) / 7) + 1;
return [dayForwards, dayBackwards, weeksForward, bilateralDayOfWeek, weeksBackwards, bilateralDayOfWeek];
}
@@ -493,10 +493,10 @@ type RemanagedDayInMonth = [
* @returns
*/
function getRemanagedDayInMonth(oldYear: number, oldMonth: number, oldDay: number, newYear: number, newMonth: number, isStrict: boolean): RemanagedDayInMonth {
- let ddata = getDayInMonth(oldYear, oldMonth, oldDay);
- let mdata = getMonthWeekStatistics(newYear, newMonth);
- let days = MONTH_DAY_COUNT[newMonth - 1]! + ((newMonth == 2 && isLeapYear(newYear)) ? 1 : 0);
- let firstDayOfWeek = dayOfWeek(newYear, newMonth, 1);
+ const ddata = getDayInMonth(oldYear, oldMonth, oldDay);
+ const mdata = getMonthWeekStatistics(newYear, newMonth);
+ const days = MONTH_DAY_COUNT[newMonth - 1]! + ((newMonth == 2 && isLeapYear(newYear)) ? 1 : 0);
+ const firstDayOfWeek = dayOfWeek(newYear, newMonth, 1);
//let lastDayOfWeek = (firstDayOfWeek + days - 1) % 7;
let methodA = undefined;
@@ -511,14 +511,14 @@ function getRemanagedDayInMonth(oldYear: number, oldMonth: number, oldDay: numbe
let methodC = undefined;
if (ddata[2] <= mdata[ddata[3]]! || !isStrict) {
- let targetWeek = Math.min(ddata[2], mdata[ddata[3]]!);
+ const targetWeek = Math.min(ddata[2], mdata[ddata[3]]!);
methodC = 1 + (targetWeek - 1) * 7 + ((ddata[3] + 7 - firstDayOfWeek) % 7);
}
let methodD = undefined;
if (ddata[4] <= mdata[ddata[5]]! || !isStrict) {
// convert to type c and calc
- let targetWeek = mdata[ddata[5]]! - Math.min(ddata[4], mdata[ddata[5]]!) + 1;
+ const targetWeek = mdata[ddata[5]]! - Math.min(ddata[4], mdata[ddata[5]]!) + 1;
methodD = 1 + (targetWeek - 1) * 7 + ((ddata[5] + 7 - firstDayOfWeek) % 7);
}
@@ -543,10 +543,10 @@ type MonthWeekStatistics = [
];
function getMonthWeekStatistics(year: number, month: number): MonthWeekStatistics {
- let days = MONTH_DAY_COUNT[month - 1]! + ((month == 2 && isLeapYear(year)) ? 1 : 0);
- let firstDayOfWeek = dayOfWeek(year, month, 1);
+ const days = MONTH_DAY_COUNT[month - 1]! + ((month == 2 && isLeapYear(year)) ? 1 : 0);
+ const firstDayOfWeek = dayOfWeek(year, month, 1);
- let result: MonthWeekStatistics = [4, 4, 4, 4, 4, 4, 4];
+ const result: MonthWeekStatistics = [4, 4, 4, 4, 4, 4, 4];
let remain = days % 7;
let week = firstDayOfWeek;
while (remain > 0) {
@@ -558,7 +558,7 @@ function getMonthWeekStatistics(year: number, month: number): MonthWeekStatistic
return result;
}
-function isLeapYear(year: number): boolean {
+export function isLeapYear(year: number): boolean {
let isLeap = false;
if (year % 4 == 0) isLeap = true;
if (year % 100 == 0) isLeap = false;
diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts
index 7fcb5a9..a323c25 100644
--- a/frontend/src/utils/utils.ts
+++ b/frontend/src/utils/utils.ts
@@ -34,7 +34,7 @@ export function format(str: string, ...args: any[]): string {
* @returns The zero-based weekday. 0 stands for Monday.
*/
export function getWeekday(date: Date): number {
- let day = date.getDay();
+ const day = date.getDay();
if (day == 0) return 6;
else return day - 1;
}
diff --git a/frontend/src/views/Collection.vue b/frontend/src/views/Collection.vue
index 38f2dd9..6848f08 100644
--- a/frontend/src/views/Collection.vue
+++ b/frontend/src/views/Collection.vue
@@ -37,13 +37,13 @@ const refreshOwnedItem = async () => {
ownedItems.value.clear();
// Fetch data
- let rv = await apiCollectionGetFullOwn(token.currentToken);
+ const rv = await apiCollectionGetFullOwn(token.currentToken);
if (typeof rv === 'undefined') {
console.error("fail to fetch owned collection");
return;
}
// Add into dict for rendering
- for (let item of rv) {
+ for (const item of rv) {
ownedItems.value.set(item[0], item);
}
@@ -53,20 +53,20 @@ const refreshOwnedItem = async () => {
}
const addOwnedItem = async () => {
- let new_name = pendingOwnedItemName.value;
+ const new_name = pendingOwnedItemName.value;
if (new_name === '') {
return
}
// first add it
- let rv = await apiCollectionAddOwn(token.currentToken, new_name);
+ const rv = await apiCollectionAddOwn(token.currentToken, new_name);
if (typeof rv === 'undefined') {
messagebox.value?.show("An add operation failed. It may caused by wrong arguments. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
return;
}
// second get its detail
- let rv2 = await apiCollectionGetDetailOwn(token.currentToken, rv);
+ const rv2 = await apiCollectionGetDetailOwn(token.currentToken, rv);
if (typeof rv2 === 'undefined') {
messagebox.value?.show("A get operation failed. It may caused by server internal error or your limited permission. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
return;
@@ -77,7 +77,7 @@ const addOwnedItem = async () => {
}
const deleteOwnedItem = async (uuid: string) => {
- let rv = await apiCollectionDeleteOwn(token.currentToken, uuid, ownedItems.value.get(uuid)![2]);
+ const rv = await apiCollectionDeleteOwn(token.currentToken, uuid, ownedItems.value.get(uuid)![2]);
if (rv) {
messagebox.value?.show("A delete operation failed. It may caused by no matched item. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
return;
@@ -97,7 +97,7 @@ const deleteOwnedItem = async (uuid: string) => {
const shareOwnedItem = async (uuid: string) => {
// if there is no editing sharing target, set it.
// otherwise override it or toggle it according to its old value.
- let old_value = sharingItemUuid.value;
+ const old_value = sharingItemUuid.value;
if (typeof old_value === 'string') {
if (old_value === uuid) {
sharingItemUuid.value = null;
@@ -112,15 +112,15 @@ const shareOwnedItem = async (uuid: string) => {
}
const updateOwnedItem = async (uuid: string, name: string) => {
- let lastChange = ownedItems.value.get(uuid)![2];
- let rv = await apiCollectionUpdateOwn(token.currentToken, uuid, name, lastChange);
+ const lastChange = ownedItems.value.get(uuid)![2];
+ const rv = await apiCollectionUpdateOwn(token.currentToken, uuid, name, lastChange);
if (typeof rv === 'undefined') {
messagebox.value?.show("An update operation failed. It may caused by wrong arguments or lost target. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
return;
}
// return value is new lastChange, so we update it.
- let row = ownedItems.value.get(uuid)!;
+ const row = ownedItems.value.get(uuid)!;
row[1] = name;
row[2] = rv;
@@ -140,8 +140,8 @@ const refreshSharingItem = async () => {
}
// fetch data
- let uuid = sharingItemUuid.value!;
- let rv = await apiCollectionGetSharing(token.currentToken, uuid);
+ const uuid = sharingItemUuid.value!;
+ const rv = await apiCollectionGetSharing(token.currentToken, uuid);
if (typeof rv === 'undefined') {
console.error(`fail to fetch sharing target for collection ${uuid}`);
return;
@@ -152,15 +152,15 @@ const refreshSharingItem = async () => {
}
const addSharingItem = async () => {
- let uuid = sharingItemUuid.value!;
- let lastChange = ownedItems.value.get(uuid)![2];
- let new_username = pendingSharingItemUsername.value;
+ const uuid = sharingItemUuid.value!;
+ const lastChange = ownedItems.value.get(uuid)![2];
+ const new_username = pendingSharingItemUsername.value;
if (new_username === '') {
return;
}
// order adding
- let rv = await apiCollectionAddSharing(token.currentToken, uuid, new_username, lastChange);
+ const rv = await apiCollectionAddSharing(token.currentToken, uuid, new_username, lastChange);
if (typeof rv === 'undefined') {
messagebox.value?.show("An add operation failed. It may caused by wrong arguments. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
return;
@@ -173,11 +173,11 @@ const addSharingItem = async () => {
}
const deleteSharingItem = async (username: string) => {
- let uuid = sharingItemUuid.value!;
- let lastChange = ownedItems.value.get(uuid)![2];
+ const uuid = sharingItemUuid.value!;
+ const lastChange = ownedItems.value.get(uuid)![2];
// order deleting
- let rv = await apiCollectionDeleteSharing(token.currentToken, uuid, username, lastChange);
+ const rv = await apiCollectionDeleteSharing(token.currentToken, uuid, username, lastChange);
if (typeof rv === 'undefined') {
messagebox.value?.show("A delete operation failed. It may caused by no matched item. Refreshing page may fix system problem. Before refreshing page, please backup all your unsaved data.");
return;