Skip to content

Commit

Permalink
Bug fixes & code improvements (#11)
Browse files Browse the repository at this point in the history
- React "refs" are widely used
- Fixed bugs in keyboard shortcuts
- Fixed a bug in the thumbnail viewer
  • Loading branch information
dinoosauro authored May 29, 2024
1 parent a1359e5 commit f6a10e9
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 178 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
};
registerServiceWorker();
}
let appVersion = "2.1.0";
let appVersion = "2.1.1";
fetch("./pdfpointer-updatecode", { cache: "no-store" }).then((res) => res.text().then((text) => { if (text.replace("\n", "") !== appVersion) if (confirm(`There's a new version of pdf-pointer. Do you want to update? [${appVersion} --> ${text.replace("\n", "")}]`)) { caches.delete("pdfpointer-cache"); location.reload(true); } }).catch((e) => { console.error(e) })).catch((e) => console.error(e)); // Check if the application code is the same as the current application version and, if not, ask the user to update
</script>

Expand Down
2 changes: 1 addition & 1 deletion public/pdfpointer-updatecode
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.1.0
2.1.1
8 changes: 4 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ declare global {
heic2any: (e: any) => Promise<Blob>
}
}
let installationPrompt: any;
export default function App() {
let installationPrompt = useRef<any>();
let [CurrentState, UpdateState] = useState<State>({});
let cardContainer = useRef<HTMLDivElement>(null);
useEffect(() => {
Expand All @@ -40,7 +40,7 @@ export default function App() {
}
window.addEventListener('beforeinstallprompt', (event) => { // Capture the request to install the PWA so that it can be displayed when the button is clicked
event.preventDefault();
installationPrompt = event;
installationPrompt.current = event;
});
}, [])
async function getNewState(file: File) {
Expand Down Expand Up @@ -106,8 +106,8 @@ export default function App() {
</div>
<i>{Lang("Install PDFPointer as an app for offline use and better integration with the OS.")}</i><br></br><br></br>
<button onClick={() => {
installationPrompt.prompt();
installationPrompt.userChoice.then((choice: { outcome: string }) => {
installationPrompt.current.prompt();
installationPrompt.current.userChoice.then((choice: { outcome: string }) => {
if (choice.outcome === "accepted") UpdateState(prevState => { return { ...prevState, hideTab: true } })
});
}}>{Lang("Install app")}</button>
Expand Down
16 changes: 11 additions & 5 deletions src/Components/CustomDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import AlertManager from "../Scripts/AlertManager";
interface Props {
category: "Color" | "Theme" // "color" for the custom color; "theme" for the custom theme
}
let typedName = ""; // Custom color name
let typedColor = ""; // Custom color value
interface SaveFilePicker {
id?: string,
suggestedName?: string,
Expand All @@ -28,6 +26,14 @@ declare global {
* @returns the CustomDisplay ReactNode
*/
export default function CustomDisplay({ category }: Props) {
/**
* Custom color name
*/
let typedName = useRef<string>("");
/**
* Custom color value
*/
let typedColor = useRef<string>("");
// Get the current theme values so that the color list can be updated
const themeValue = [{ ref: "background", desc: Lang("Background color"), value: getComputedStyle(document.body).getPropertyValue("--background") },
{ ref: "text", desc: Lang("Text color"), value: getComputedStyle(document.body).getPropertyValue("--text") },
Expand Down Expand Up @@ -85,11 +91,11 @@ export default function CustomDisplay({ category }: Props) {
return <>
<div style={{ display: "flex", justifyContent: category === "Color" ? "center" : "", overflow: "auto" }}>
{category === "Color" ? <>
<input type="color" style={{ height: "42px" }} onInput={(e) => typedColor = e.currentTarget.value}></input>
<input style={{ marginLeft: "10px", width: "fit-content", height: "38px" }} onInput={(e) => typedName = e.currentTarget.value} type="text" placeholder={Lang("Write the color name")}></input>
<input type="color" style={{ height: "42px" }} onInput={(e) => typedColor.current = e.currentTarget.value}></input>
<input style={{ marginLeft: "10px", width: "fit-content", height: "38px" }} onInput={(e) => typedName.current = e.currentTarget.value} type="text" placeholder={Lang("Write the color name")}></input>
<button style={{ marginLeft: "10px", width: "fit-content" }} onClick={() => { // The button that'll add the new color to the list
let getContent = JSON.parse(localStorage.getItem(`PDFPointer-Custom${category}`) ?? "[]") as CustomProp[];
getContent.push({ name: typedName, value: typedColor, id: getId() })
getContent.push({ name: typedName.current, value: typedColor.current, id: getId() })
localStorage.setItem(`PDFPointer-Custom${category}`, JSON.stringify(getContent));
forceRefresh(nothing + 1);
}}>{Lang("Add")}</button>
Expand Down
6 changes: 3 additions & 3 deletions src/Components/DropdownItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ interface Props {
backdropColor?: boolean,
defaultValueRef?: keyof DrawingStoredOptions
}
let clientX = 0;
/**
*
* @param children the content that'll be always shown,
Expand All @@ -28,6 +27,7 @@ export default function DropdownItem({ children, content, title, disableAutoDisa
/**
* Hide the dropdown content with an opacity transition
*/
let clientX = useRef<number>(0);
async function disappear() {
if (ref) {
if (ref.current) ref.current.style.opacity = "0";
Expand All @@ -49,10 +49,10 @@ export default function DropdownItem({ children, content, title, disableAutoDisa
return <>
<span>
<span onClick={(e) => { // Show (or hide) the dropdown item (the button is clicked)
clientX = e.clientX;
clientX.current = e.clientX;
UpdateDropdown(!ShowDropdown)
}}>{children}</span>
{ShowDropdown && <div style={{ backgroundColor: backdropColor ? "var(--firststruct)" : "", position: "fixed", left: clientX + (window.innerWidth * 45 / 100) < window.innerWidth ? `${clientX}px` : undefined, right: clientX + (window.innerWidth * 45 / 100) > window.innerWidth ? `${window.innerWidth - clientX - 10}px` : undefined }} className="dropdownOpen opacity" ref={ref}><h3>{title}</h3><div onClick={async () => {
{ShowDropdown && <div style={{ backgroundColor: backdropColor ? "var(--firststruct)" : "", position: "fixed", left: clientX.current + (window.innerWidth * 45 / 100) < window.innerWidth ? `${clientX.current}px` : undefined, right: clientX.current + (window.innerWidth * 45 / 100) > window.innerWidth ? `${window.innerWidth - clientX.current - 10}px` : undefined }} className="dropdownOpen opacity" ref={ref}><h3>{title}</h3><div onClick={async () => {
if (!disableAutoDisappear) await disappear();
}}>
<div style={{ position: "absolute", top: 15, right: 15 }} className="simplePointer" onClick={disappear}><DynamicImg id="minimize"></DynamicImg></div>
Expand Down
50 changes: 24 additions & 26 deletions src/Components/ExportDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,6 @@ import Lang from "../Scripts/LanguageTranslations";
import ImageExport from "../Scripts/Export";
import * as PDFJS from "pdfjs-dist";

/**
* The custom values for the PDF exportation as image
*/
let exportValue = {
img: "png",
pages: "",
annotations: true,
scale: 2,
zip: false,
quality: 0.85,
filter: ""
}

interface Props {
pdfObj?: PDFJS.PDFDocumentProxy,
imgObj?: HTMLImageElement
Expand All @@ -28,38 +15,49 @@ interface Props {
*/
export default function ExportDialog({ pdfObj, imgObj }: Props) {
let exportButton = useRef<HTMLButtonElement>(null);

/**
* The custom values for the PDF exportation as image
*/
let exportValue = useRef({
img: "png",
pages: "",
annotations: true,
scale: 2,
zip: false,
quality: 0.85,
filter: ""
})
return <div>
<label>{Lang("Export image in the")} <select defaultValue={exportValue.img} onChange={(e) => exportValue.img = (e.target as HTMLSelectElement).value}>
<label>{Lang("Export image in the")} <select defaultValue={exportValue.current.img} onChange={(e) => exportValue.current.img = (e.target as HTMLSelectElement).value}>
<option value={"jpeg"}>JPG</option>
<option value={"png"}>PNG</option>
{document.createElement("canvas").toDataURL("image/webp").startsWith("data:image/webp") && <option value={"webp"}>WEBP</option>}
</select> {Lang("format")}</label><br></br><br></br>
{pdfObj && <>
<label>{Lang("Write the number of pages to export:")}</label><br></br>
<i style={{ fontSize: "0.75em" }}>{Lang(`Separate pages with a comma, or add multiple pages with a dash: "1-5,7"`)}</i><br></br>
<input style={{ marginTop: "10px" }} type="text" defaultValue={exportValue.pages} onInput={(e) => {
exportValue.pages = (e.target as HTMLInputElement).value;
if (exportButton.current) exportButton.current.disabled = !/^[0-9,-]*$/.test(exportValue.pages);
<input style={{ marginTop: "10px" }} type="text" defaultValue={exportValue.current.pages} onInput={(e) => {
exportValue.current.pages = (e.target as HTMLInputElement).value;
if (exportButton.current) exportButton.current.disabled = !/^[0-9,-]*$/.test(exportValue.current.pages);
}}></input><br></br><br></br></>}
<label>{Lang("Choose the size of the output image:")}</label><br></br>
<input type="range" min={0.5} max={8} step={0.01} defaultValue={exportValue.scale} onChange={(e) => { exportValue.scale = parseFloat((e.target as HTMLInputElement).value) }}></input><br></br><br></br>
<input type="range" min={0.5} max={8} step={0.01} defaultValue={exportValue.current.scale} onChange={(e) => { exportValue.current.scale = parseFloat((e.target as HTMLInputElement).value) }}></input><br></br><br></br>
<label>{Lang("Choose the quality of the output image:")}</label><br></br>
<input type="range" min={0.01} max={1} step={0.01} defaultValue={exportValue.quality} onChange={(e) => { exportValue.quality = parseFloat((e.target as HTMLInputElement).value) }}></input><br></br><br></br>
<input type="range" min={0.01} max={1} step={0.01} defaultValue={exportValue.current.quality} onChange={(e) => { exportValue.current.quality = parseFloat((e.target as HTMLInputElement).value) }}></input><br></br><br></br>
<div style={{ display: "flex", alignItems: "center" }}>
<input type="checkbox" defaultChecked={exportValue.annotations} onChange={e => exportValue.annotations = (e.target as HTMLInputElement).checked}></input><label>{Lang("Export also annotations")}</label></div><br></br>
<input type="checkbox" defaultChecked={exportValue.current.annotations} onChange={e => exportValue.current.annotations = (e.target as HTMLInputElement).checked}></input><label>{Lang("Export also annotations")}</label></div><br></br>
{document.createElement("canvas").getContext("2d")?.filter !== undefined && <><div style={{ display: "flex", alignItems: "center" }}>
<input type="checkbox" defaultChecked={exportValue.filter !== ""} onChange={e => {
<input type="checkbox" defaultChecked={exportValue.current.filter !== ""} onChange={e => {
let getFilterCanvas = Array.from(document.querySelectorAll("canvas")).filter(e => e.style.filter !== "");
if ((e.target as HTMLInputElement).checked && getFilterCanvas.length !== 0) { exportValue.filter = getFilterCanvas[0].style.filter; } else exportValue.filter = ""
if ((e.target as HTMLInputElement).checked && getFilterCanvas.length !== 0) { exportValue.current.filter = getFilterCanvas[0].style.filter; } else exportValue.current.filter = ""
}}></input><label>{Lang("Apply filters to exported image")}</label></div><br></br>
</>}
<div style={{ display: "flex", alignItems: "center" }}>
<input type="checkbox" defaultChecked={exportValue.zip} onChange={e => exportValue.zip = (e.target as HTMLInputElement).checked}></input><label>{Lang("Save output as a .zip file")}</label></div><br></br><br></br>
<input type="checkbox" defaultChecked={exportValue.current.zip} onChange={e => exportValue.current.zip = (e.target as HTMLInputElement).checked}></input><label>{Lang("Save output as a .zip file")}</label></div><br></br><br></br>
<button ref={exportButton} onClick={async () => {
let handle;
try { // If the user doesn't want to save the file as ZIP, and the File System API is supported, use the "showDirectoryPicker" method
handle = (exportValue.pages.indexOf("-") !== -1 || exportValue.pages.indexOf(",") !== -1) ? window.showDirectoryPicker !== undefined && !exportValue.zip ? await window.showDirectoryPicker({ mode: "readwrite", id: "PDFPointer-PDFExportFolder" }) : undefined : window.showSaveFilePicker !== undefined && !exportValue.zip ? await window.showSaveFilePicker({ id: "PDFPointer-PDFExportFolder", types: [{ "description": "The selected image", accept: { [`image/${exportValue.img}`]: [`.${exportValue.img === "jpeg" ? "jpg" : exportValue.img}`] } }] }) : undefined; // If there are no "," or "-" the item to download is only an image, therefore try to use the File System API for a single file. Otherwise, try to use the File System API for folders
handle = (exportValue.current.pages.indexOf("-") !== -1 || exportValue.current.pages.indexOf(",") !== -1) ? window.showDirectoryPicker !== undefined && !exportValue.current.zip ? await window.showDirectoryPicker({ mode: "readwrite", id: "PDFPointer-PDFExportFolder" }) : undefined : window.showSaveFilePicker !== undefined && !exportValue.current.zip ? await window.showSaveFilePicker({ id: "PDFPointer-PDFExportFolder", types: [{ "description": "The selected image", accept: { [`image/${exportValue.current.img}`]: [`.${exportValue.current.img === "jpeg" ? "jpg" : exportValue.current.img}`] } }] }) : undefined; // If there are no "," or "-" the item to download is only an image, therefore try to use the File System API for a single file. Otherwise, try to use the File System API for folders
} catch (ex) {
console.warn({
type: "RejectedPicker",
Expand All @@ -68,7 +66,7 @@ export default function ExportDialog({ pdfObj, imgObj }: Props) {
ex: ex
})
}
ImageExport({ imgType: exportValue.img, pages: exportValue.pages, getAnnotations: exportValue.annotations, pdfObj: pdfObj, scale: exportValue.scale, useZip: exportValue.zip, quality: exportValue.quality, handle: handle, filter: exportValue.filter, imgObj: imgObj })
ImageExport({ imgType: exportValue.current.img, pages: exportValue.current.pages, getAnnotations: exportValue.current.annotations, pdfObj: pdfObj, scale: exportValue.current.scale, useZip: exportValue.current.zip, quality: exportValue.current.quality, handle: handle, filter: exportValue.current.filter, imgObj: imgObj })
}}>{Lang("Export image(s)")}</button>
</div>
}
Loading

0 comments on commit f6a10e9

Please sign in to comment.