319 lines
14 KiB
JavaScript
319 lines
14 KiB
JavaScript
#include msgbox.jsx
|
|
#include utility.js
|
|
#include ext/eeprom.js
|
|
|
|
let MszForumEditorAllowClose = false;
|
|
|
|
const MszForumEditor = function(form) {
|
|
if(!(form instanceof Element))
|
|
throw 'form must be an instance of element';
|
|
|
|
const buttonsElem = form.querySelector('.js-forum-posting-buttons'),
|
|
textElem = form.querySelector('.js-forum-posting-text'),
|
|
parserElem = form.querySelector('.js-forum-posting-parser'),
|
|
previewElem = form.querySelector('.js-forum-posting-preview'),
|
|
modeElem = form.querySelector('.js-forum-posting-mode'),
|
|
markupBtns = form.querySelectorAll('.js-forum-posting-markup');
|
|
|
|
const bbBtns = $q('.forum__post__actions--bbcode'),
|
|
mdBtns = $q('.forum__post__actions--markdown');
|
|
|
|
let lastPostText = '',
|
|
lastPostParser;
|
|
|
|
MszEEPROM.init()
|
|
.catch(() => console.error('Failed to initialise EEPROM'))
|
|
.then(() => {
|
|
const eepromClient = new EEPROM(peepApp, `${peepPath}/uploads`, '');
|
|
const eepromHistory = <div class="eeprom-widget-history-items"/>;
|
|
|
|
const eepromHandleFileUpload = file => {
|
|
const uploadElemNameValue = <div class="eeprom-widget-file-name-value" title={file.name}>{file.name}</div>;
|
|
const uploadElemName = <a class="eeprom-widget-file-name" target="_blank">{uploadElemNameValue}</a>;
|
|
const uploadElemProgressText = <div class="eeprom-widget-file-progress">Please wait...</div>;
|
|
const uploadElemProgressBarValue = <div class="eeprom-widget-file-bar-fill" style={{ width: '0%' }}/>;
|
|
const uploadElem = <div class="eeprom-widget-file">
|
|
<div class="eeprom-widget-file-info">
|
|
{uploadElemName}
|
|
{uploadElemProgressText}
|
|
</div>
|
|
<div class="eeprom-widget-file-bar">
|
|
{uploadElemProgressBarValue}
|
|
</div>
|
|
</div>;
|
|
|
|
if(eepromHistory.children.length > 0)
|
|
$ib(eepromHistory.firstChild, uploadElem);
|
|
else
|
|
eepromHistory.appendChild(uploadElem);
|
|
|
|
const explodeUploadElem = () => $r(uploadElem);
|
|
const uploadTask = eepromClient.createUpload(file);
|
|
|
|
uploadTask.onProgress = function(progressInfo) {
|
|
const progressValue = `${progressInfo.progress}%`;
|
|
uploadElemProgressBarValue.style.width = progressValue;
|
|
uploadElemProgressText.textContent = `${progressValue} (${progressInfo.total - progressInfo.loaded} bytes remaining)`;
|
|
};
|
|
|
|
uploadTask.onFailure = function(errorInfo) {
|
|
if(!errorInfo.userAborted) {
|
|
let errorText = 'Was unable to upload file.';
|
|
|
|
switch(errorInfo.error) {
|
|
case EEPROM.ERR_INVALID:
|
|
errorText = 'Upload request was invalid.';
|
|
break;
|
|
case EEPROM.ERR_AUTH:
|
|
errorText = 'Upload authentication failed, refresh and try again.';
|
|
break;
|
|
case EEPROM.ERR_ACCESS:
|
|
errorText = "You're not allowed to upload files.";
|
|
break;
|
|
case EEPROM.ERR_GONE:
|
|
errorText = 'Upload client has a configuration error or the server is gone.';
|
|
break;
|
|
case EEPROM.ERR_DMCA:
|
|
errorText = 'This file has been uploaded before and was removed for copyright reasons, you cannot upload this file.';
|
|
break;
|
|
case EEPROM.ERR_SERVER:
|
|
errorText = 'Upload server returned a critical error, try again later.';
|
|
break;
|
|
case EEPROM.ERR_SIZE:
|
|
if(errorInfo.maxSize < 1)
|
|
errorText = 'Selected file is too large.';
|
|
else {
|
|
const types = ['bytes', 'KB', 'MB', 'GB', 'TB'],
|
|
typeIndex = parseInt(Math.floor(Math.log(errorInfo.maxSize) / Math.log(1024))),
|
|
number = Math.round(errorInfo.maxSize / Math.pow(1024, _i), 2);
|
|
|
|
errorText = `Upload may not be larger than ${number} ${types[typeIndex]}.`;
|
|
}
|
|
break;
|
|
}
|
|
|
|
uploadElem.classList.add('eeprom-widget-file-fail');
|
|
uploadElemProgressText.textContent = errorText;
|
|
MszShowMessageBox(errorText, 'Upload Error');
|
|
}
|
|
};
|
|
|
|
uploadTask.onComplete = function(fileInfo) {
|
|
uploadElem.classList.add('eeprom-widget-file-done');
|
|
uploadElemName.href = fileInfo.url;
|
|
uploadElemProgressText.textContent = '';
|
|
|
|
const insertTheLinkIntoTheBoxEx2 = function() {
|
|
const parserMode = parseInt(parserElem.value);
|
|
let insertText = location.protocol + fileInfo.url;
|
|
|
|
if(parserMode == 1) { // bbcode
|
|
if(fileInfo.isImage())
|
|
insertText = `[img]${fileInfo.url}[/img]`;
|
|
else if(fileInfo.isAudio())
|
|
insertText = `[audio]${fileInfo.url}[/audio]`;
|
|
else if(fileInfo.isVideo())
|
|
insertText = `[video]${fileInfo.url}[/video]`;
|
|
} else if(parserMode == 2) { // markdown
|
|
if(fileInfo.isMedia())
|
|
insertText = `![](${fileInfo.url})`;
|
|
}
|
|
|
|
$insertTags(textElem, insertText, '');
|
|
textElem.value = textElem.value.trim();
|
|
};
|
|
|
|
uploadElemProgressText.appendChild(<a href="javascript:void(0)" onclick={() => insertTheLinkIntoTheBoxEx2()}>Insert</a>);
|
|
uploadElemProgressText.appendChild($t(' '));
|
|
uploadElemProgressText.appendChild(<a href="javascript:void(0)" onclick={() => {
|
|
eepromClient.deleteUpload(fileInfo).start();
|
|
explodeUploadElem();
|
|
}}>Delete</a>);
|
|
|
|
insertTheLinkIntoTheBoxEx2();
|
|
};
|
|
|
|
uploadTask.start();
|
|
};
|
|
|
|
const eepromFormInput = <input type="file" multiple={true} class="eeprom-widget-form-input"
|
|
onchange={() => {
|
|
const files = eepromFormInput.files;
|
|
for(const file of files)
|
|
eepromHandleFileUpload(file);
|
|
eepromFormInput.value = '';
|
|
}}/>;
|
|
|
|
const eepromForm = <label class="eeprom-widget-form">
|
|
{eepromFormInput}
|
|
<div class="eeprom-widget-form-text">
|
|
Select Files...
|
|
</div>
|
|
</label>;
|
|
|
|
const eepromWidget = <div class="eeprom-widget">
|
|
{eepromForm}
|
|
<div class="eeprom-widget-history">
|
|
{eepromHistory}
|
|
</div>
|
|
</div>;
|
|
|
|
form.appendChild(eepromWidget);
|
|
|
|
textElem.addEventListener('paste', ev => {
|
|
if(ev.clipboardData && ev.clipboardData.files.length > 0) {
|
|
ev.preventDefault();
|
|
|
|
const files = ev.clipboardData.files;
|
|
for(const file of files)
|
|
eepromHandleFileUpload(file);
|
|
}
|
|
});
|
|
|
|
document.body.addEventListener('dragenter', ev => {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
});
|
|
document.body.addEventListener('dragover', ev => {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
});
|
|
document.body.addEventListener('dragleave', ev => {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
});
|
|
document.body.addEventListener('drop', ev => {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
|
|
if(ev.dataTransfer && ev.dataTransfer.files.length > 0) {
|
|
const files = ev.dataTransfer.files;
|
|
for(const file of files)
|
|
eepromHandleFileUpload(file);
|
|
}
|
|
});
|
|
});
|
|
|
|
// hack: don't prompt user when hitting submit, really need to make this not stupid.
|
|
buttonsElem.firstChild.addEventListener('click', () => MszForumEditorAllowClose = true);
|
|
|
|
window.addEventListener('beforeunload', function(ev) {
|
|
if(!MszForumEditorAllowClose && textElem.value.length > 0) {
|
|
ev.preventDefault();
|
|
ev.returnValue = '';
|
|
}
|
|
});
|
|
|
|
for(const button of markupBtns)
|
|
button.addEventListener('click', () => $insertTags(textElem, button.dataset.tagOpen, button.dataset.tagClose));
|
|
|
|
const switchButtons = parser => {
|
|
parser = parseInt(parser);
|
|
bbBtns.hidden = parser !== 1;
|
|
mdBtns.hidden = parser !== 2;
|
|
};
|
|
|
|
const renderPreview = async (parser, text) => {
|
|
if(typeof text !== 'string')
|
|
return '';
|
|
|
|
const formData = new FormData;
|
|
formData.append('post[mode]', 'preview');
|
|
formData.append('post[text]', text);
|
|
formData.append('post[parser]', parseInt(parser));
|
|
|
|
const result = await $x.post('/forum/posting.php', { authed: true }, formData);
|
|
|
|
return result.body();
|
|
};
|
|
|
|
const previewBtn = <button class="input__button" type="button" value="preview">Preview</button>;
|
|
previewBtn.addEventListener('click', function() {
|
|
if(previewBtn.value === 'back') {
|
|
previewElem.setAttribute('hidden', 'hidden');
|
|
textElem.removeAttribute('hidden');
|
|
previewBtn.value = 'preview';
|
|
previewBtn.textContent = 'Preview';
|
|
modeElem.textContent = modeElem.dataset.original;
|
|
modeElem.dataset.original = null;
|
|
} else {
|
|
const postText = textElem.value,
|
|
postParser = parseInt(parserElem.value);
|
|
|
|
if(lastPostText === postText && lastPostParser === postParser) {
|
|
previewElem.removeAttribute('hidden');
|
|
textElem.setAttribute('hidden', 'hidden');
|
|
previewBtn.value = 'back';
|
|
previewBtn.textContent = 'Edit';
|
|
modeElem.dataset.original = modeElem.textContent;
|
|
modeElem.textContent = 'Previewing';
|
|
return;
|
|
}
|
|
|
|
parserElem.setAttribute('disabled', 'disabled');
|
|
previewBtn.setAttribute('disabled', 'disabled');
|
|
previewBtn.classList.add('input__button--busy');
|
|
|
|
renderPreview(postParser, postText)
|
|
.catch(() => {
|
|
previewElem.innerHTML = '';
|
|
MszShowMessageBox('Failed to render preview.');
|
|
})
|
|
.then(body => {
|
|
previewElem.classList.toggle('markdown', postParser === 2);
|
|
|
|
lastPostText = postText;
|
|
lastPostParser = postParser;
|
|
previewElem.innerHTML = body;
|
|
|
|
MszEmbed.handle($qa('.js-msz-embed-media'));
|
|
|
|
previewElem.removeAttribute('hidden');
|
|
textElem.setAttribute('hidden', 'hidden');
|
|
previewBtn.value = 'back';
|
|
previewBtn.textContent = 'Back';
|
|
previewBtn.removeAttribute('disabled');
|
|
parserElem.removeAttribute('disabled');
|
|
previewBtn.classList.remove('input__button--busy');
|
|
modeElem.dataset.original = modeElem.textContent;
|
|
modeElem.textContent = 'Previewing';
|
|
});
|
|
}
|
|
});
|
|
buttonsElem.insertBefore(previewBtn, buttonsElem.firstChild);
|
|
|
|
switchButtons(parserElem.value);
|
|
|
|
parserElem.addEventListener('change', () => {
|
|
const postParser = parseInt(parserElem.value);
|
|
switchButtons(postParser);
|
|
|
|
if(previewElem.hasAttribute('hidden'))
|
|
return;
|
|
|
|
// dunno if this would even be possible, but ech
|
|
if(postParser === lastPostParser)
|
|
return;
|
|
|
|
parserElem.setAttribute('disabled', 'disabled');
|
|
previewBtn.setAttribute('disabled', 'disabled');
|
|
previewBtn.classList.add('input__button--busy');
|
|
|
|
renderPreview(postParser, lastPostText)
|
|
.catch(() => {
|
|
previewElem.innerHTML = '';
|
|
MszShowMessageBox('Failed to render preview.');
|
|
})
|
|
.then(body => {
|
|
previewElem.classList.add('markdown', postParser === 2);
|
|
lastPostParser = postParser;
|
|
previewElem.innerHTML = body;
|
|
|
|
MszEmbed.handle($qa('.js-msz-embed-media'));
|
|
|
|
previewBtn.removeAttribute('disabled');
|
|
parserElem.removeAttribute('disabled');
|
|
previewBtn.classList.remove('input__button--busy');
|
|
});
|
|
});
|
|
};
|