Skip to content

Commit

Permalink
Updated README, added copy action support for preformatted element data
Browse files Browse the repository at this point in the history
  • Loading branch information
bennettfrazier committed Sep 19, 2024
1 parent b3cb46d commit ff8db21
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 1 deletion.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ Analyze HTTP Archive (HAR) files to export, filter, and group the data to JSON

HAR File Analyzer repo can run on its own by simply cloning the repository to your local and then opening the index.html file in the browser.

For more information on how to HAR files should be handled (as it can contain sensitive data such as auth tokens or cookies), see Okta's documentation on [Generating and analyzing HAR files](https://auth0.com/docs/troubleshoot/troubleshooting-tools/generate-and-analyze-har-files).

To run the app, do the following:

1. `git clone https://github.com/bennettfrazier/har-file-analyzer.git`
2. `cd har-file-analyzer`
3. `open index.html`

The app allows you to traverse through the HAR file entries, and export the specific data related to each entry. There is simple filtering, search (which could likely be improved) and multi-selection capabilities.
The app allows you to traverse through the HAR file entries, and export the specific data related to each entry. There is simple filtering, search (which could likely be improved) and multi-selection capabilities. I wrote this app to attempt to unpack HAR entries to view server requests / responses and export with a similar data structure, as Chrome Dev tools will sometimes not display data for custom mimeTypes that actually display JSON.

Under the hood this is using [Water.css](https://watercss.kognise.dev/) for simple styling, [Fuse.js](https://www.fusejs.io/) for fuzzy client-side search, and vanilla JavaScript for JSON tree traversing.

Expand Down
79 changes: 79 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ function buildJsonTree(container, data, path, seen, dataRoot) {
// Display the formatted string
const pre = document.createElement('pre');
pre.textContent = formatJSONString(textContent);

addCopyButtonToPre(pre);
li.appendChild(pre);
}

Expand Down Expand Up @@ -550,6 +552,7 @@ function buildJsonTree(container, data, path, seen, dataRoot) {
// Display the formatted string
const pre = document.createElement('pre');
pre.textContent = formatJSONString(textContent);
addCopyButtonToPre(pre);
li.appendChild(pre);
}
} else if (isObject) {
Expand Down Expand Up @@ -579,6 +582,82 @@ function buildJsonTree(container, data, path, seen, dataRoot) {
container.appendChild(ul);
}

function addCopyButtonToPre(preElement) {
// Check if the element is a <pre>
if (!(preElement instanceof HTMLElement) || preElement.tagName.toLowerCase() !== 'pre') {
console.error('addCopyButtonToPre: Provided element is not a <pre> element.');
return;
}

// Avoid adding multiple buttons to the same <pre>
if (preElement.querySelector('.copy-button')) {
console.warn('addCopyButtonToPre: <pre> element already has a copy button.');
return;
}

// Create the button element
const button = document.createElement('button');
button.className = 'copy-button';
button.textContent = 'Copy';

// Define the copy action
button.addEventListener('click', async () => {
// Disable the button to prevent multiple clicks
button.disabled = true;

try {
// Clone the <pre> element to exclude the button's text
const clone = preElement.cloneNode(true);
const buttonInClone = clone.querySelector('.copy-button');
if (buttonInClone) {
buttonInClone.remove(); // Remove the button from the clone
}

// Get the text content from the cloned <pre>
const textToCopy = clone.textContent.trim();

// Use the Clipboard API if available
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(textToCopy);
} else {
// Fallback method for older browsers
const textarea = document.createElement('textarea');
textarea.value = textToCopy;
// Prevent scrolling to bottom
textarea.style.position = 'fixed';
textarea.style.top = '0';
textarea.style.left = '-9999px';
document.body.appendChild(textarea);
textarea.focus();
textarea.select();

const successful = document.execCommand('copy');
if (!successful) throw new Error('Failed to copy text');

document.body.removeChild(textarea);
}

// Provide feedback to the user
button.textContent = 'Copied!';
button.classList.add('copied');

// Revert the button text after 2 seconds
setTimeout(() => {
button.textContent = 'Copy';
button.classList.remove('copied');
button.disabled = false;
}, 2000);
} catch (err) {
console.error('Error copying text: ', err);
alert('Failed to copy text. Please try again.');
button.disabled = false;
}
});

// Append the button to the <pre> element
preElement.appendChild(button);
}

function formatJSONString(jsonString) {
try {
const jsonObj = JSON.parse(jsonString);
Expand Down
32 changes: 32 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,38 @@ input {
overflow-y: auto;
white-space: pre-wrap;
max-height: 300px;
position: relative;
}
.copy-button {
position: absolute;
top: 10px;
right: 10px;
padding: 5px 10px;
font-size: 12px;
cursor: pointer;
background-color: black;
color: white;
border: none;
border-radius: 3px;
opacity: 0.8;
transition: opacity 0.3s, background-color 0.3s;
}

.copy-button:hover {
opacity: 1;
background-color: #45a049;
}

.copy-button:active {
background-color: #3e8e41;
}

.copy-button.copied {
background-color: #2196f3;
}

.copy-button.copied:hover {
background-color: #1e88e5;
}

.expanded-content {
Expand Down

0 comments on commit ff8db21

Please sign in to comment.