discourse-legacysite-perl/site/forum/editor_image.html
2024-06-17 22:24:05 +10:00

438 lines
17 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%~set page_mode = $in.editor_type%><%if not page_mode or page_mode ne message%><%set page_mode = 'post'%><%endif%>
<html>
<head>
<title>Insert Image</title>
<link type="text/css" rel="stylesheet" media="screen" href="<%static_url%>/editor/editor_dialog.css">
<script type="text/javascript" src="<%static_url%>/js/utils.js"></script>
<script type="text/javascript" src="<%static_url%>/editor/editor_dialog.js"></script>
<script type="text/javascript">
//<![CDATA[
var src = {}, activeSource, sourceTypes = ['url', 'file', 'inline'];
var inlineImages = [];
var inlines = [];
if (window.opener.getInlineAttachments)
inlines = opener.getInlineAttachments();
<%~if attachment_uploaded%>
inlines.push(['<%escape_js attachment_uploaded%>', 'temp', '<%attachment_uploaded_id%>']);
<%~endif%>
function checkSource(submitting) {
if (activeSource && src[activeSource + '-input'] && src[activeSource + '-input'].value && src[activeSource + '-input'].value.match(/\S/)) {
submit.disabled = false;
if (submitting) {
if (activeSource == 'file')
return true;
else
submitWrapper();
}
}
else
submit.disabled = true;
return false;
}
function changeElement() {
activeSource = false;
for (var i = 0; i < sourceTypes.length; i++) {
if (src[sourceTypes[i]] && src[sourceTypes[i]].checked) {
activeSource = sourceTypes[i];
break;
}
}
if (!activeSource) return;
for (var i = 0; i < sourceTypes.length; i++) {
if (src[sourceTypes[i]])
src[sourceTypes[i] + '-row'].style.display = activeSource == sourceTypes[i] ? 'block' : 'none';
}
if (document.getElementById('src-file'))
{
if (document.getElementById('src-file').checked) {
document.getElementById('src-file-size-slider').style.display = 'flex';
document.getElementById('src-file-quality-slider').style.display = 'flex';
document.getElementById('src-file-size-orig').style.display = 'block';
document.getElementById('src-file-size-resize').style.display = 'block';
}
else {
document.getElementById('src-file-size-slider').style.display = 'none';
document.getElementById('src-file-quality-slider').style.display = 'none';
document.getElementById('src-file-size-orig').style.display = 'none';
document.getElementById('src-file-size-resize').style.display = 'none';
}
}
}
function init() {
<%~if attachment_uploaded%>
// The upload succeeded: make the parent page refresh the attachment list
if (opener.refreshAttachmentList)
opener.refreshAttachmentList();
<%~endif%>
// We need to copy the temp_id from the parent document.
document.getElementById('temp_id').value = opener.document.getElementById('temp_id').value ? opener.document.getElementById('temp_id').value : "foo";
// Also copy over forum_id, parent_post_id, and post_id, if they exist.
var hidden = [opener.document.getElementById('forum_id'), opener.document.getElementById('parent_post_id'), opener.document.getElementById('post_id')];
for (var i = 0; i < hidden.length; i++) {
if (hidden[i]) {
var h = document.createElement('input');
h.type = 'hidden';
h.name = hidden[i].name;
h.value = hidden[i].value;
document.getElementById('image_form').appendChild(h);
}
}
var eventType = isIE ? 'propertychange' : 'change';
for (var i = 0; i < sourceTypes.length; i++) {
var sourceType = sourceTypes[i];
src[sourceType] = document.getElementById('src-' + sourceType);
src[sourceType + '-input'] = document.getElementById('src-' + sourceType + '-input');
src[sourceType + '-label'] = document.getElementById('src-' + sourceType + '-label');
src[sourceType + '-value'] = document.getElementById('src-' + sourceType + '-value');
src[sourceType + '-row'] = document.getElementById('src-' + sourceType + '-row');
if (src[sourceType]) registerEvent(src[sourceType], eventType, changeElement);
}
if (inlines.length > 0) {
for (i = 0; i < inlines.length; i++) {
var filename = inlines[i][0];
var inlineRadio;
// Hack around a weird IE bug where setting the name attribute
// below results in the radio button not showing its state properly
try {
inlineRadio = document.createElement('<input type="radio" name="inline_image" />');
}
catch (e) {
inlineRadio = document.createElement('input');
}
inlineRadio.type = 'radio';
inlineRadio.name = 'inline_image';
inlineRadio.id = 'inline_image' + i;
inlineRadio.value = filename;
<%~if attachment_uploaded%>
if (filename == '<%escape_js attachment_uploaded%>') {
inlineRadio.checked = true;
src['inline-input'].value = filename;
}
<%~endif%>
var inlineLabel = document.createElement('label');
inlineLabel.appendChild(document.createTextNode(filename));
inlineLabel.htmlFor = 'inline_image' + i;
var box = document.createElement('span');
box.appendChild(inlineRadio);
box.appendChild(inlineLabel);
src['inline-value'].appendChild(box);
inlineImages[inlineImages.length] = inlineRadio;
registerEvent(inlineRadio, 'click', function(radioBox) { return function () { src['inline-input'].value = radioBox.value; }; }(inlineRadio));
}
}
else {
src['inline'].parentNode.removeChild(src['inline']);
src['inline-label'].parentNode.removeChild(src['inline-label']);
src['inline-row'].parentNode.removeChild(src['inline-row']);
delete src['inline'];
delete src['inline-label'];
delete src['inline-row'];
}
if (!opener.canAttach) {
src['file'].parentNode.removeChild(src['file']);
src['file-label'].parentNode.removeChild(src['file-label']);
src['file-row'].parentNode.removeChild(src['file-row']);
delete src['file'];
delete src['file-label'];
delete src['file-row'];
}
submit = document.getElementById('submit');
changeElement();
setInterval(function () { checkSource() }, 250);
if (src['url'] && src['url'].checked) document.getElementById('src-url-input').focus();
<%~if error_loop.length%>
alert('Error:\n<%loop error_loop%><%escape_js loop_value%><%unless last%>\n<%endunless%><%endloop%>');
<%~elsif attachment_uploaded%>
if (true || confirm("submit form?")) submitWrapper();
<%~endif%>
}
function submitWrapper () {
if (activeSource == 'inline') {
var att_type = 'temp', att_id = 0;
for (var i = 0; i < inlines.length; i++) {
if (inlines[i][0] == src['inline-input'].value) {
att_type = inlines[i][1];
att_id = inlines[i][2];
break;
}
}
var url = '<%set url = GForum::SEO::url(params => "do=${page_mode}_attachment")%><%escape_js url%>;' + att_type + 'att_id=' + att_id;
if (att_type == 'temp')
url += ';<%if page_mode eq "post"%>post_unique<%else%>temp_id<%endif%>=' + document.getElementById('temp_id').value;
src['url-input'].value = url;
}
submitForm();
}
registerEvent(window, 'load', init);
//]]>
</script>
</head>
<body id="editor_image">
<!--form id="image_form" enctype="multipart/form-data" onsubmit="return checkSource(true)"-->
<form id="image_form" action="<%GForum::SEO::url()%>" method="post" enctype="multipart/form-data" onsubmit="return checkSource(true)">
<%hidden_form%>
<input type="hidden" name="do" value="<%page_mode%>_attachment_upload" />
<input type="hidden" id="temp_id" name="temp_id" value="" /><%-- populated from parent window by init() --%>
<input type="hidden" name="redo" value="<%this_do%>" />
<div id="form">
<div class="row">
<label class="name">Insert Image from:</label>
<input type="radio" id="src-url" name="src-type" class="radio"<%unless attachment_uploaded or error_loop.length%> checked<%endunless%>><label id="src-url-label" for="src-url" accesskey="u"><u>U</u>RL</label>
<%~unless attachment_uploaded%>
<input type="radio" id="src-file" name="src-type" class="radio"<%if error_loop.length%> checked<%endif%>><label id="src-file-label" for="src-file" accesskey="f"><u>F</u>ile</label>
<%~endunless%>
<input type="radio" id="src-inline" name="src-type" class="radio"<%if attachment_uploaded%> checked<%endunless%>><label id="src-inline-label" for="src-inline" accesskey="i"><u>I</u>nline Attachment</label>
</div>
<div id="src-url-row" class="row">
<label for="src-url-input" class="name" accesskey="s">Image <u>S</u>ource:</label>
<input type="text" id="src-url-input" value="" class="text">
</div>
<%~unless attachment_uploaded%>
<div id="src-file-row" class="row">
<label for="src-file-input" class="name" accesskey="m">I<u>m</u>age Upload:</label>
<input type="file" accept="image/*" id="src-file-input" name="<%if page_mode eq message%>msg<%else%>post<%endif%>_attachment_orig" class="file">
<input type="hidden" name="<%if page_mode eq message%>message<%else%>post<%endif%>_attachment_inline" value="1">
</div>
<div id="src-file-size-slider" style="display: none; align-items: center; gap: 8px;">
Size:
<input type="range" min="10" max="<%~if in.forum_id eq "1" %>1024<%~else %>256<%~endif%>" value="<%~if in.forum_id eq "1" %>512<%~else %>128<%~endif%>" id="input-size" style="max-width: 200px;"/>
<span id="target-size"></span>
</div>
<div id="src-file-quality-slider" style="display: none; align-items: center; gap: 8px;">
Quality:
<input type="range" min="10" max="100" value="90" id="input-quality" style="max-width: 200px;"/>
</div>
<div id="src-file-size-orig" style="display: none;">Original: <span id="original-dimensions"></span> - <span id="original-bytesize"></span></div>
<div id="src-file-size-resize" style="display: none;">Resized: <span id="resized-dimensions"></span> - <span id="resized-bytesize"></span></div>
<br />
<div>
<img style="width: 500px; object-fit: scale-down;" id="output-img"></img>
</div>
<%~endunless%>
<div id="src-inline-row" class="row">
<input type="hidden" id="src-inline-input" value="">
<label class="name">I<u>n</u>line Attachment:</label>
<div id="src-inline-value" class="value"><%-- populated by init() --%></div>
</div>
</div>
<div class="buttons">
<input type="submit" id="submit" value="OK" class="submit">
<input type="button" value="Cancel" class="button" onclick="window.close()">
</div>
</form>
<div id="output-box"></div>
</body>
<%~unless attachment_uploaded%>
<script>
let sourceImg = null
let sourceSize = 0
let initialized = false
let inputImg = document.getElementById('src-file-input')
let outputImg = document.getElementById('output-img')
let inputSize = document.getElementById('input-size')
let targetSize = document.getElementById('target-size')
let inputQuality = document.getElementById('input-quality')
let originalDimensions = document.getElementById('original-dimensions')
let resizedDimensions = document.getElementById('resized-dimensions')
let originalBytesize = document.getElementById('original-bytesize')
let resizedBytesize = document.getElementById('resized-bytesize')
//action="<%GForum::SEO::url()%>" method="post"
const form = document.forms.namedItem("image_form");
form.addEventListener(
"submit",
(event) => {
event.preventDefault();
const output = document.getElementById("output-box");
const formData = new FormData(form);
formData.append("CustomField", "This is some extra data");
const imgBlob = imageToBlob(outputImg.src, 'image/jpeg');
var imgPath = inputImg.value;
const imgName = imgPath.replace(/^.*?([^\\\/]*)$/, '$1');
formData.append("post_attachment", imgBlob, imgName);
const request = new XMLHttpRequest();
request.open("POST", "<%GForum::SEO::url()%>", true);
request.onload = (progress) => {
output.innerHTML =
request.status === 200
? "Uploaded!"
: `Error ${request.status} occurred when trying to upload your file.<br />`;
if ( request.status === 200 )
{
const winUrl = URL.createObjectURL( new Blob([request.responseText], { type: "text/html" }));
const win = location.replace(winUrl);
}
else
{
// error...
}
};
request.send(formData);
},
false
);
function resizeImage(image, size, quality)
{
let index = 0
let canvases = [document.createElement('canvas'), document.createElement('canvas')]
{
canvases[index].width = image.naturalWidth
canvases[index].height = image.naturalHeight
const ctx0 = canvases[index].getContext('2d')
ctx0.drawImage(image, 0, 0)
}
let finalWidth = Math.floor(image.naturalWidth * size)
let finalHeight = Math.floor(image.naturalHeight * size)
let iter = Math.floor(Math.sqrt((1 / size)))
for(let i = 0; i < iter; i++)
{
let canvasSrc = canvases[index]
let canvasDst = canvases[1 - index]
const ctxSrc = canvasSrc.getContext('2d')
const ctxDst = canvasDst.getContext('2d')
if(i == (iter - 1))
{
canvasDst.width = finalWidth
canvasDst.height = finalHeight
}
else
{
canvasDst.width = canvasSrc.width / 2
canvasDst.height = canvasSrc.height / 2
}
ctxDst.drawImage(canvasSrc, 0, 0, canvasSrc.width, canvasSrc.height, 0, 0, canvasDst.width, canvasDst.height)
index = 1 - index
}
let dataURL = canvases[index].toDataURL('image/jpeg', quality)
return dataURL
}
function getDataURLByteSize(d)
{
let parts = d.split(",")
let b64size = parts[1].length
let b64padding = parts[1].slice(-4).split('').filter(x => x == '=').length
return 3 * ((b64size / 4)) - b64padding
}
function onResizeSourceImg()
{
if(!sourceImg) return
targetSize.textContent = `${inputSize.value} KB`
let dataOriginal = resizeImage(sourceImg, 1, inputQuality.value / 100)
let sizeOriginal = getDataURLByteSize(dataOriginal)
let target = 1
if ( !initialized )
target = Math.min( sizeOriginal, <%~if in.forum_id eq "1" %>1024000<%~else %>256000<%~endif%> );
else
target = inputSize.value * 1024;
let imgRatio = Math.min( sourceImg.naturalWidth / sourceImg.naturalHeight, sourceImg.naturalHeight / sourceImg.naturalWidth );
let ratio = imgRatio * Math.sqrt( Math.min(1, target / sizeOriginal))
let dataURL = resizeImage(sourceImg, ratio, inputQuality.value / 100)
outputImg.src = dataURL
let size = getDataURLByteSize(dataURL)
resizedBytesize.textContent = `${Math.floor(size / 1024)} KB`
if ( !initialized )
{
targetSize.textContent = `${Math.floor(size / 1024)} KB`
inputSize.value = Math.floor(size / 1024)
initialized = true
}
}
onResizeSourceImg()
outputImg.onload = () => {
if(!sourceImg) return
resizedDimensions.textContent = `${outputImg.naturalWidth} x ${outputImg.naturalHeight}`
}
inputSize.addEventListener("input", e => {
onResizeSourceImg()
})
inputQuality.addEventListener("input", e => {
onResizeSourceImg()
})
inputImg.addEventListener("change", e => {
let files = e.target.files
if(files.length == 0) return
let file = files[0]
let fr = new FileReader()
fr.onload = () => {
let image = new Image()
image.onload = () => {
sourceImg = image
sourceSize = file.size
originalDimensions.textContent = `${image.naturalWidth} x ${image.naturalHeight}`
originalBytesize.textContent = `${Math.floor(file.size / 1024)} KB`
//inputSize.setAttribute('max', image.naturalWidth)
//inputSize.value = image.naturalWidth * 0.5
onResizeSourceImg()
}
image.src = fr.result
}
fr.readAsDataURL(file)
})
function imageToBlob(image, mime)
{
let byteString = atob(image.split(',')[1]);
let ab = new ArrayBuffer(byteString.length);
let ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) ia[i] = byteString.charCodeAt(i);
let bb = new Blob([ab], { type: mime });
return bb
}
</script>
<%~endunless%>
</html>