mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-09-26 07:16:13 +00:00
WIP
This commit is contained in:
@@ -10,6 +10,8 @@
|
||||
const highlight_submit_ignore_url="{{url_for('ui.ui_edit.highlight_submit_ignore_url', uuid=uuid)}}";
|
||||
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
|
||||
<script src="{{url_for('static_content', group='js', filename='snippet-to-image.js')}}"></script>
|
||||
<script src="{{url_for('static_content', group='js', filename='diff-overview.js')}}" defer></script>
|
||||
|
||||
<div id="settings">
|
||||
@@ -94,6 +96,14 @@
|
||||
</div>
|
||||
|
||||
<div class="tab-pane-inner" id="text">
|
||||
<button id="share-as-image-btn" onclick="diffToJpeg()" title="Share diff as image" style="float: right; margin: 10px; padding: 8px 12px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: middle; margin-right: 4px;">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
||||
<circle cx="8.5" cy="8.5" r="1.5"></circle>
|
||||
<polyline points="21 15 16 10 5 21"></polyline>
|
||||
</svg>
|
||||
Share as Image
|
||||
</button>
|
||||
{% if password_enabled_and_share_is_off %}
|
||||
<div class="tip">Pro-tip: You can enable <strong>"share access when password is enabled"</strong> from settings</div>
|
||||
{% endif %}
|
||||
@@ -103,7 +113,7 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td id="diff-col" class="highlightable-filter">
|
||||
<pre style="border-left: 2px solid #ddd;">{{ content| diff_unescape_difference_spans }}</pre>
|
||||
<pre id="difference" style="border-left: 2px solid #ddd;">{{ content| diff_unescape_difference_spans }}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* snippet-to-image.js
|
||||
* Converts the selected diff content to a JPEG image for sharing/downloading
|
||||
*/
|
||||
|
||||
async function diffToJpeg() {
|
||||
// Check if html2canvas is loaded
|
||||
if (typeof html2canvas === 'undefined') {
|
||||
alert("html2canvas library is not loaded yet. Please wait a moment and try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the user's text selection
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
|
||||
alert("Please select the text/lines you want to capture first by highlighting with your mouse.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Show a loading indicator
|
||||
const btn = document.getElementById("share-as-image-btn");
|
||||
const originalText = btn ? btn.innerHTML : '';
|
||||
if (btn) {
|
||||
btn.innerHTML = 'Generating...';
|
||||
btn.style.opacity = "0.5";
|
||||
btn.style.pointerEvents = "none";
|
||||
}
|
||||
|
||||
let tempElement = null;
|
||||
|
||||
try {
|
||||
// Get the selected content with HTML (preserves spans and styling)
|
||||
const range = selection.getRangeAt(0);
|
||||
const selectedFragment = range.cloneContents();
|
||||
|
||||
// Create a temporary element to hold the selected content
|
||||
tempElement = document.createElement("pre");
|
||||
tempElement.id = "temp-capture-element";
|
||||
tempElement.appendChild(selectedFragment);
|
||||
|
||||
// Copy styles from the original #difference element
|
||||
const originalPre = document.getElementById("difference");
|
||||
const originalStyles = window.getComputedStyle(originalPre);
|
||||
|
||||
tempElement.style.position = "absolute";
|
||||
tempElement.style.left = "-9999px";
|
||||
tempElement.style.top = "0";
|
||||
tempElement.style.whiteSpace = "pre-wrap";
|
||||
tempElement.style.fontFamily = originalStyles.fontFamily;
|
||||
tempElement.style.fontSize = originalStyles.fontSize;
|
||||
tempElement.style.lineHeight = originalStyles.lineHeight;
|
||||
tempElement.style.color = originalStyles.color;
|
||||
tempElement.style.backgroundColor = "#ffffff";
|
||||
tempElement.style.padding = "10px";
|
||||
tempElement.style.border = originalStyles.border;
|
||||
tempElement.style.width = "auto";
|
||||
tempElement.style.maxWidth = originalPre.offsetWidth + "px";
|
||||
|
||||
// Add to document so it can be measured and captured
|
||||
document.body.appendChild(tempElement);
|
||||
|
||||
console.log("Capturing selection...");
|
||||
console.log("Temp element dimensions:", tempElement.offsetWidth, "x", tempElement.offsetHeight);
|
||||
|
||||
// Give browser time to render
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
const canvas = await html2canvas(tempElement, {
|
||||
scale: 2, // higher quality
|
||||
useCORS: true,
|
||||
allowTaint: true,
|
||||
logging: false,
|
||||
backgroundColor: '#ffffff',
|
||||
scrollX: 0,
|
||||
scrollY: 0
|
||||
});
|
||||
|
||||
console.log("Canvas created:", canvas.width, "x", canvas.height);
|
||||
|
||||
if (canvas.width === 0 || canvas.height === 0) {
|
||||
throw new Error("Canvas is empty - no content captured");
|
||||
}
|
||||
|
||||
// Convert to JPEG
|
||||
const jpeg = canvas.toDataURL("image/jpeg", 0.95);
|
||||
|
||||
if (jpeg === "data:," || jpeg.length < 100) {
|
||||
throw new Error("Failed to generate image data");
|
||||
}
|
||||
|
||||
// Open in new window
|
||||
const win = window.open();
|
||||
if (win) {
|
||||
win.document.write('<html><head><title>Diff Screenshot</title></head><body style="margin:0;"><img src="' + jpeg + '" alt="Diff Screenshot" style="max-width:100%;"/></body></html>');
|
||||
} else {
|
||||
// Fallback to download if popup blocked
|
||||
const a = document.createElement("a");
|
||||
a.href = jpeg;
|
||||
a.download = "diff-snapshot-" + Date.now() + ".jpg";
|
||||
a.click();
|
||||
}
|
||||
|
||||
// Clear the selection
|
||||
selection.removeAllRanges();
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error generating image:", error);
|
||||
alert("Failed to generate image: " + error.message);
|
||||
} finally {
|
||||
// Clean up temporary element
|
||||
if (tempElement && tempElement.parentNode) {
|
||||
tempElement.parentNode.removeChild(tempElement);
|
||||
}
|
||||
|
||||
// Reset button state
|
||||
if (btn) {
|
||||
btn.innerHTML = originalText;
|
||||
btn.style.opacity = "1";
|
||||
btn.style.pointerEvents = "auto";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user