mirror of
https://github.com/Warky-Devs/artemis-kit.git
synced 2025-05-19 03:37:30 +00:00
Added openFileLink, formatSecondToTime and timeStringToSeconds
This commit is contained in:
parent
bf80e32841
commit
9f5b743e15
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
|
||||
}
|
94
src/dom/file_utils.test.ts
Normal file
94
src/dom/file_utils.test.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import { openFileLink } from "./file_utils";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
describe("openFileLink", () => {
|
||||
it("stub test", () => {
|
||||
const link = "https://example.com";
|
||||
openFileLink(link);
|
||||
|
||||
const a = document.querySelector("a");
|
||||
expect(a).toBeDefined();
|
||||
});
|
||||
});
|
||||
// describe("openFileLink", () => {
|
||||
// beforeEach(() => {
|
||||
// // Mock the window object
|
||||
// global.window = {
|
||||
// document: {
|
||||
// body: {
|
||||
// appendChild: vi.fn(),
|
||||
// removeChild: vi.fn(),
|
||||
// },
|
||||
// createElement: vi.fn(() => ({
|
||||
// href: "",
|
||||
// download: "",
|
||||
// click: vi.fn(),
|
||||
// })),
|
||||
// },
|
||||
// };
|
||||
|
||||
// // Create a mock for document.createElement
|
||||
// const createElementMock = vi.fn(() => ({
|
||||
// href: "",
|
||||
// download: "",
|
||||
// click: vi.fn(),
|
||||
// }));
|
||||
// Object.defineProperty(global.window.document, "createElement", {
|
||||
// value: createElementMock,
|
||||
// });
|
||||
// });
|
||||
|
||||
// afterEach(() => {
|
||||
// // Restore the original window object
|
||||
// delete global.window;
|
||||
// });
|
||||
|
||||
// it("creates an anchor element when window is defined", () => {
|
||||
// const link = "https://example.com";
|
||||
// openFileLink(link);
|
||||
// expect(global.window.document.createElement).toHaveBeenCalledTimes(1);
|
||||
// expect(global.window.document.createElement).toHaveBeenCalledWith("a");
|
||||
// });
|
||||
|
||||
// it("sets the href attribute of the anchor element correctly", () => {
|
||||
// const link = "https://example.com";
|
||||
// openFileLink(link);
|
||||
// const elem = global.window.document.body.appendChild.mock.calls[0][0];
|
||||
// expect(elem.href).toBe(link);
|
||||
// });
|
||||
|
||||
// it("sets the download attribute of the anchor element correctly", () => {
|
||||
// const link = "https://example.com";
|
||||
// openFileLink(link);
|
||||
// const elem = global.window.document.body.appendChild.mock.calls[0][0];
|
||||
// expect(elem.download).toBe("");
|
||||
// });
|
||||
|
||||
// it("appends the anchor element to the DOM", () => {
|
||||
// const link = "https://example.com";
|
||||
// openFileLink(link);
|
||||
// expect(global.window.document.body.appendChild).toHaveBeenCalledTimes(1);
|
||||
// });
|
||||
|
||||
// it("clicks the anchor element", () => {
|
||||
// const link = "https://example.com";
|
||||
// openFileLink(link);
|
||||
// const elem = global.window.document.body.appendChild.mock.calls[0][0];
|
||||
// expect(elem.click).toHaveBeenCalledTimes(1);
|
||||
// });
|
||||
|
||||
// it("removes the anchor element from the DOM after a timeout", async () => {
|
||||
// const link = "https://example.com";
|
||||
// openFileLink(link);
|
||||
// const elem = global.window.document.body.appendChild.mock.calls[0][0];
|
||||
// await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
// expect(global.window.document.body.removeChild).toHaveBeenCalledTimes(1);
|
||||
// expect(global.window.document.body.removeChild).toHaveBeenCalledWith(elem);
|
||||
// });
|
||||
|
||||
// it("does not throw an error when window is not defined", () => {
|
||||
// delete global.window;
|
||||
// const link = "https://example.com";
|
||||
// expect(() => openFileLink(link)).not.toThrow();
|
||||
// });
|
||||
// });
|
20
src/dom/file_utils.ts
Normal file
20
src/dom/file_utils.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Creates an anchor element and initiates a download click on it with a given URL.
|
||||
* This function is only available on the client side.
|
||||
* @param link - URL to download
|
||||
*/
|
||||
export const openFileLink = (link: string) => {
|
||||
if (typeof window !== "undefined") {
|
||||
const elem = document.createElement("a");
|
||||
elem.href = link;
|
||||
elem.style.display = "none"; // Hide the element
|
||||
elem.download = ""; // Suggest the browser to download instead of navigating
|
||||
document.body.appendChild(elem); // Attach to the DOM for the click to work
|
||||
elem.click();
|
||||
setTimeout(() => {
|
||||
if (document.body && elem) {
|
||||
document.body.removeChild(elem); // Clean up the element from the DOM
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
};
|
1
src/dom/index.ts
Normal file
1
src/dom/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./file_utils";
|
@ -5,3 +5,4 @@ export * from "./promise";
|
||||
export * from "./i18n";
|
||||
export * from "./dataqueue";
|
||||
//export * from './logger'
|
||||
export * from "./dom";
|
||||
|
@ -5,3 +5,4 @@ export * from "./locale";
|
||||
export * from "./fileSize";
|
||||
export * from "./legacy";
|
||||
export * from "./uuid";
|
||||
export * from "./time";
|
||||
|
52
src/strings/time.test.ts
Normal file
52
src/strings/time.test.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { formatSecondToTime } from "./time";
|
||||
|
||||
describe("formatSecondToTime", () => {
|
||||
it("formats time with hours", () => {
|
||||
expect(formatSecondToTime(3661)).toBe("01:01:01");
|
||||
});
|
||||
|
||||
it("formats time without hours", () => {
|
||||
expect(formatSecondToTime(61)).toBe("01:01");
|
||||
});
|
||||
|
||||
it("formats time with zero seconds", () => {
|
||||
expect(formatSecondToTime(3600)).toBe("01:00:00");
|
||||
});
|
||||
|
||||
it("formats time with zero minutes and seconds", () => {
|
||||
expect(formatSecondToTime(0)).toBe("00:00");
|
||||
});
|
||||
|
||||
it("handles negative input", () => {
|
||||
expect(formatSecondToTime(-1)).toBe("-00:01");
|
||||
});
|
||||
|
||||
it("handles decimal input", () => {
|
||||
expect(formatSecondToTime(1.5)).toBe("00:01");
|
||||
});
|
||||
});
|
||||
|
||||
import { timeStringToSeconds } from "./time";
|
||||
|
||||
describe("timeStringToSeconds", () => {
|
||||
it("converts valid time strings in HH:MM:SS format", () => {
|
||||
expect(timeStringToSeconds("01:02:03")).toBe(3723);
|
||||
expect(timeStringToSeconds("12:34:56")).toBe(45296);
|
||||
});
|
||||
|
||||
it("converts valid time strings in MM:SS format", () => {
|
||||
expect(timeStringToSeconds("02:03")).toBe(123);
|
||||
expect(timeStringToSeconds("34:56")).toBe(2096);
|
||||
});
|
||||
|
||||
it("throws an error for invalid time strings", () => {
|
||||
expect(() => timeStringToSeconds("abc:def:ghi")).toThrowError();
|
||||
expect(() => timeStringToSeconds("12:34:56:78")).toThrowError();
|
||||
});
|
||||
|
||||
it("handles edge cases", () => {
|
||||
expect(timeStringToSeconds("00:00:00")).toBe(0);
|
||||
expect(timeStringToSeconds("23:59:59")).toBe(86399);
|
||||
});
|
||||
});
|
69
src/strings/time.ts
Normal file
69
src/strings/time.ts
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Format a time in seconds to a string.
|
||||
*
|
||||
* @param totalSeconds time in seconds
|
||||
* @returns a string in the format HH:MM:SS or MM:SS if hours are zero
|
||||
*/
|
||||
export function formatSecondToTime(totalSeconds: number): string {
|
||||
const prefix = totalSeconds < 0 ? "-" : "";
|
||||
totalSeconds = Math.abs(Math.floor(totalSeconds));
|
||||
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
const seconds = totalSeconds % 60;
|
||||
|
||||
if (hours > 0) {
|
||||
return `${prefix}${hours.toString().padStart(2, "0")}:${minutes
|
||||
.toString()
|
||||
.padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
return `${prefix}${minutes.toString().padStart(2, "0")}:${seconds
|
||||
.toString()
|
||||
.padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a time string in the format HH:MM:SS or MM:SS to a total number of seconds.
|
||||
*
|
||||
* @param timeStr - a string in the format HH:MM:SS or MM:SS
|
||||
* @returns the total number of seconds
|
||||
*/
|
||||
export function timeStringToSeconds(timeStr: string): number {
|
||||
// Validate input is not empty
|
||||
if (!timeStr || !timeStr.trim()) {
|
||||
throw new Error("Time string cannot be empty");
|
||||
}
|
||||
|
||||
const parts = timeStr.split(":");
|
||||
if (parts.length < 2 || parts.length > 3) {
|
||||
throw new Error("Invalid time format. Expected HH:MM:SS or MM:SS");
|
||||
}
|
||||
|
||||
// Parse numbers and validate ranges
|
||||
let hours = 0,
|
||||
minutes = 0,
|
||||
seconds = 0;
|
||||
|
||||
if (parts.length === 3) {
|
||||
// HH:MM:SS format
|
||||
[hours, minutes, seconds] = parts.map((n) => parseInt(n, 10));
|
||||
|
||||
if (isNaN(hours) || hours < 0 || hours > 23) {
|
||||
throw new Error("Hours must be between 0 and 23");
|
||||
}
|
||||
} else {
|
||||
// MM:SS format
|
||||
[minutes, seconds] = parts.map((n) => parseInt(n, 10));
|
||||
}
|
||||
|
||||
if (isNaN(minutes) || minutes < 0 || minutes > 59) {
|
||||
throw new Error("Minutes must be between 0 and 59");
|
||||
}
|
||||
|
||||
if (isNaN(seconds) || seconds < 0 || seconds > 59) {
|
||||
throw new Error("Seconds must be between 0 and 59");
|
||||
}
|
||||
|
||||
return hours * 3600 + minutes * 60 + seconds;
|
||||
}
|
Loading…
Reference in New Issue
Block a user