440 lines
17 KiB
HTML
440 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 = window.open(
|
|
winUrl,
|
|
"_self"
|
|
);
|
|
win.opener = opener;
|
|
}
|
|
};
|
|
|
|
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>
|