2024-01-24 21:53:26 +00:00
|
|
|
#include msgbox.jsx
|
2024-01-30 23:47:02 +00:00
|
|
|
#include parsing.js
|
2024-01-24 21:53:26 +00:00
|
|
|
#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'),
|
2024-01-30 23:47:02 +00:00
|
|
|
markupActs = form.querySelector('.js-forum-posting-actions');
|
2024-01-24 21:53:26 +00:00
|
|
|
|
|
|
|
let lastPostText = '',
|
|
|
|
lastPostParser;
|
|
|
|
|
|
|
|
MszEEPROM.init()
|
|
|
|
.catch(() => console.error('Failed to initialise EEPROM'))
|
|
|
|
.then(() => {
|
2024-02-02 21:42:40 +00:00
|
|
|
const eepromClient = new EEPROM(peepApp, peepPath);
|
2024-01-24 21:53:26 +00:00
|
|
|
const eepromHistory = <div class="eeprom-widget-history-items"/>;
|
|
|
|
|
2024-02-02 21:42:40 +00:00
|
|
|
const eepromHandleFileUpload = async file => {
|
2024-01-24 21:53:26 +00:00
|
|
|
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);
|
2024-02-02 21:42:40 +00:00
|
|
|
const uploadTask = eepromClient.create(file);
|
2024-01-24 21:53:26 +00:00
|
|
|
|
2024-02-02 21:42:40 +00:00
|
|
|
uploadTask.onProgress(prog => {
|
|
|
|
const progress = `}%`;
|
|
|
|
uploadElemProgressBarValue.style.width = `${Math.ceil(prog.progress * 100)}%`;
|
|
|
|
uploadElemProgressText.textContent = `${prog.progress.toLocaleString(undefined, { style: 'percent' })} (${prog.total - prog.loaded} bytes remaining)`;
|
|
|
|
});
|
|
|
|
|
|
|
|
try {
|
|
|
|
const fileInfo = await uploadTask.start();
|
2024-01-24 21:53:26 +00:00
|
|
|
|
|
|
|
uploadElem.classList.add('eeprom-widget-file-done');
|
|
|
|
uploadElemName.href = fileInfo.url;
|
|
|
|
uploadElemProgressText.textContent = '';
|
|
|
|
|
2024-02-02 21:42:40 +00:00
|
|
|
const insertTheLinkIntoTheBoxEx2 = () => {
|
2024-01-24 21:53:26 +00:00
|
|
|
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={() => {
|
2024-02-02 21:42:40 +00:00
|
|
|
eepromClient.delete(fileInfo)
|
|
|
|
.then(() => explodeUploadElem())
|
|
|
|
.catch(ex => {
|
|
|
|
console.error(ex);
|
|
|
|
MszShowMessageBox(ex, 'Upload Error');
|
|
|
|
});
|
2024-01-24 21:53:26 +00:00
|
|
|
}}>Delete</a>);
|
|
|
|
|
|
|
|
insertTheLinkIntoTheBoxEx2();
|
2024-02-02 21:42:40 +00:00
|
|
|
} catch(ex) {
|
|
|
|
let errorText = 'Upload aborted.';
|
|
|
|
|
|
|
|
if(!ex.aborted) {
|
|
|
|
console.error(ex);
|
|
|
|
errorText = ex.toString();
|
|
|
|
}
|
2024-01-24 21:53:26 +00:00
|
|
|
|
2024-02-02 21:42:40 +00:00
|
|
|
uploadElem.classList.add('eeprom-widget-file-fail');
|
|
|
|
uploadElemProgressText.textContent = errorText;
|
|
|
|
await MszShowMessageBox(errorText, 'Upload Error');
|
|
|
|
}
|
2024-01-24 21:53:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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 = '';
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const switchButtons = parser => {
|
2024-01-30 23:47:02 +00:00
|
|
|
$rc(markupActs);
|
|
|
|
|
|
|
|
const tags = MszParsing.getTagsFor(parser);
|
|
|
|
for(const tag of tags)
|
|
|
|
markupActs.appendChild(<button class={['forum__post__action', 'forum__post__action--tag', `forum__post__action--${tag.name}`]}
|
|
|
|
type="button" title={tag.summary} onclick={() => $insertTags(textElem, tag.open, tag.close)}>
|
|
|
|
<i class={tag.icon}/>
|
|
|
|
</button>);
|
2024-01-24 21:53:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|