mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-03-04 02:20:19 +01:00
Addition of the Show JavaScript tool (#4877)
# Description of Changes - Added the show javascript tool. --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details.
This commit is contained in:
137
frontend/src/core/hooks/tools/showJS/useShowJSOperation.ts
Normal file
137
frontend/src/core/hooks/tools/showJS/useShowJSOperation.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import apiClient from '@app/services/apiClient';
|
||||
import type { ToolOperationHook } from '@app/hooks/tools/shared/useToolOperation';
|
||||
import type { StirlingFile } from '@app/types/fileContext';
|
||||
import { extractErrorMessage } from '@app/utils/toolErrorHandler';
|
||||
import type { ShowJSParameters } from '@app/hooks/tools/showJS/useShowJSParameters';
|
||||
import type { ResponseType } from 'axios';
|
||||
|
||||
export interface ShowJSOperationHook extends ToolOperationHook<ShowJSParameters> {
|
||||
scriptText: string | null;
|
||||
}
|
||||
|
||||
export const useShowJSOperation = (): ShowJSOperationHook => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [status, setStatus] = useState('');
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
const [downloadUrl, setDownloadUrl] = useState<string | null>(null);
|
||||
const [downloadFilename, setDownloadFilename] = useState('');
|
||||
const [scriptText, setScriptText] = useState<string | null>(null);
|
||||
|
||||
const cancelRequested = useRef(false);
|
||||
const previousUrl = useRef<string | null>(null);
|
||||
|
||||
const cleanupDownloadUrl = useCallback(() => {
|
||||
if (previousUrl.current) {
|
||||
URL.revokeObjectURL(previousUrl.current);
|
||||
previousUrl.current = null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const resetResults = useCallback(() => {
|
||||
cancelRequested.current = false;
|
||||
setScriptText(null);
|
||||
setFiles([]);
|
||||
cleanupDownloadUrl();
|
||||
setDownloadUrl(null);
|
||||
setDownloadFilename('');
|
||||
setStatus('');
|
||||
setErrorMessage(null);
|
||||
}, [cleanupDownloadUrl]);
|
||||
|
||||
const clearError = useCallback(() => {
|
||||
setErrorMessage(null);
|
||||
}, []);
|
||||
|
||||
const executeOperation = useCallback(
|
||||
async (_params: ShowJSParameters, selectedFiles: StirlingFile[]) => {
|
||||
if (selectedFiles.length === 0) {
|
||||
setErrorMessage(t('noFileSelected', 'No files selected'));
|
||||
return;
|
||||
}
|
||||
|
||||
cancelRequested.current = false;
|
||||
setIsLoading(true);
|
||||
setStatus(t('showJS.processing', 'Extracting JavaScript...'));
|
||||
setErrorMessage(null);
|
||||
setScriptText(null);
|
||||
setFiles([]);
|
||||
cleanupDownloadUrl();
|
||||
setDownloadUrl(null);
|
||||
setDownloadFilename('');
|
||||
|
||||
try {
|
||||
const file = selectedFiles[0];
|
||||
const formData = new FormData();
|
||||
formData.append('fileInput', file);
|
||||
|
||||
const response = await apiClient.post('/api/v1/misc/show-javascript', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
responseType: 'text' as ResponseType,
|
||||
transformResponse: [(data) => data],
|
||||
});
|
||||
|
||||
const text: string = typeof response.data === 'string' ? response.data : '';
|
||||
setScriptText(text);
|
||||
|
||||
// Optional: prepare a downloadable file
|
||||
const outFile = new File([text], (file.name?.replace(/\.[^.]+$/, '') || 'extracted') + '.js', {
|
||||
type: 'application/javascript',
|
||||
});
|
||||
setFiles([outFile]);
|
||||
const blobUrl = URL.createObjectURL(outFile);
|
||||
previousUrl.current = blobUrl;
|
||||
setDownloadUrl(blobUrl);
|
||||
setDownloadFilename(outFile.name);
|
||||
|
||||
setStatus(t('showJS.done', 'JavaScript extracted'));
|
||||
} catch (error: unknown) {
|
||||
setErrorMessage(extractErrorMessage(error));
|
||||
setStatus('');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
},
|
||||
[t, cleanupDownloadUrl]
|
||||
);
|
||||
|
||||
const cancelOperation = useCallback(() => {
|
||||
cancelRequested.current = true;
|
||||
setIsLoading(false);
|
||||
setStatus(t('operationCancelled', 'Operation cancelled'));
|
||||
}, [t]);
|
||||
|
||||
const undoOperation = useCallback(async () => {
|
||||
// No-op for this tool
|
||||
setStatus(t('nothingToUndo', 'Nothing to undo'));
|
||||
}, [t]);
|
||||
|
||||
return {
|
||||
// State (align with ToolOperationHook)
|
||||
files,
|
||||
thumbnails: [],
|
||||
isGeneratingThumbnails: false,
|
||||
downloadUrl,
|
||||
downloadFilename,
|
||||
isLoading,
|
||||
status,
|
||||
errorMessage,
|
||||
progress: null,
|
||||
|
||||
// Custom state
|
||||
scriptText,
|
||||
|
||||
// Actions
|
||||
executeOperation,
|
||||
resetResults,
|
||||
clearError,
|
||||
cancelOperation,
|
||||
undoOperation,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
21
frontend/src/core/hooks/tools/showJS/useShowJSParameters.ts
Normal file
21
frontend/src/core/hooks/tools/showJS/useShowJSParameters.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { useBaseParameters, type BaseParametersHook } from '@app/hooks/tools/shared/useBaseParameters';
|
||||
import { BaseParameters } from '@app/types/parameters';
|
||||
|
||||
export interface ShowJSParameters extends BaseParameters {
|
||||
// Extends BaseParameters - ready for future parameter additions if needed
|
||||
}
|
||||
|
||||
export const defaultParameters: ShowJSParameters = {
|
||||
// No parameters needed
|
||||
};
|
||||
|
||||
|
||||
export type ShowJSParametersHook = BaseParametersHook<ShowJSParameters>;
|
||||
|
||||
export const useShowJSParameters = (): ShowJSParametersHook => {
|
||||
return useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: 'show-javascript',
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user