diff --git a/assets/css/misuzu/eeprom.css b/assets/css/misuzu/eeprom.css new file mode 100644 index 0000000..b678aa8 --- /dev/null +++ b/assets/css/misuzu/eeprom.css @@ -0,0 +1,104 @@ +.eeprom-widget { + background-color: var(--container-colour); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); + text-shadow: 0 1px 4px #000; + display: flex; + min-height: 50px; +} + +.eeprom-widget-form { + display: flex; + text-align: center; + justify-content: center; + align-items: center; + flex: 0 0 auto; + min-width: 154px; /* same width as sidebar */ + background-color: #aaa1; + transition: background-color .2s; +} +.eeprom-widget-form-input { + display: none; + visibility: hidden; +} +.eeprom-widget-form-text { + font-size: 1.4em; + line-height: 1.5em; +} +.eeprom-widget-form:focus, +.eeprom-widget-form:hover { + background-color: #fff1; +} +.eeprom-widget-form:active { + background-color: #ccc1; +} + +.eeprom-widget-history { + overflow-y: auto; + scrollbar-width: thin; +} +.eeprom-widget-history-items { + display: flex; + padding: 0 3px; +} + +.eeprom-widget-file { + margin: 4px 1px; + padding-top: 2px; /* adjust for the progress bar */ + border: 1px solid var(--accent-colour); + border-radius: 2px; + overflow: hidden; + width: 200px; + flex: 0 0 auto; +} +.eeprom-widget-file-fail { + --accent-color: #c00; +} +.eeprom-widget-file-info { + padding: 0 2px; +} +.eeprom-widget-file-name { + color: #fff; + text-decoration: none; +} +.eeprom-widget-file-name-value { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.eeprom-widget-file-name:hover, +.eeprom-widget-file-name:focus { + text-decoration: underline; +} +.eeprom-widget-file-progress { + font-size: .9em; + line-height: 1.4em; + text-align: right; + padding: 0 2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.eeprom-widget-file-progress a { + color: var(--accent-colour); + text-decoration: none; +} +.eeprom-widget-file-progress a:hover, +.eeprom-widget-file-progress a:focus { + text-decoration: underline; +} +.eeprom-widget-file-bar { + width: 100%; + height: 2px; + display: flex; + justify-content: flex-start; + align-items: flex-end; +} +.eeprom-widget-file-bar-fill { + width: 0%; + height: 2px; + background-color: var(--accent-colour); + transition: width .1s, height .1s; +} +.eeprom-widget-file-done .eeprom-widget-file-bar-fill { + height: 0; +} diff --git a/assets/js/misuzu/forum/editor.js b/assets/js/misuzu/forum/editor.js index 252797d..4603fdf 100644 --- a/assets/js/misuzu/forum/editor.js +++ b/assets/js/misuzu/forum/editor.js @@ -1,11 +1,11 @@ Misuzu.Forum.Editor = {}; Misuzu.Forum.Editor.allowWindowClose = false; Misuzu.Forum.Editor.init = function() { - var postingForm = $q('.js-forum-posting'); + const postingForm = $q('.js-forum-posting'); if(!postingForm) return; - var postingButtons = postingForm.querySelector('.js-forum-posting-buttons'), + const postingButtons = postingForm.querySelector('.js-forum-posting-buttons'), postingText = postingForm.querySelector('.js-forum-posting-text'), postingParser = postingForm.querySelector('.js-forum-posting-parser'), postingPreview = postingForm.querySelector('.js-forum-posting-preview'), @@ -15,6 +15,277 @@ Misuzu.Forum.Editor.init = function() { markdownButtons = $q('.forum__post__actions--markdown'), markupButtons = $qa('.forum__post__action--tag'); + // Initialise EEPROM, code sucks ass but it's getting nuked soon again anyway + if(typeof peepPath === 'string') + document.body.appendChild($e({ + tag: 'script', + attrs: { + src: peepPath + '/eeprom.js', + charset: 'utf-8', + type: 'text/javascript', + onload: function() { + const eepromClient = new EEPROM(peepApp, peepPath + '/uploads', ''); + + const eepromHistory = $e({ + attrs: { + className: 'eeprom-widget-history-items', + }, + }); + + const eepromHandleFileUpload = function(file) { + const uploadElemNameValue = $e({ + attrs: { + className: 'eeprom-widget-file-name-value', + title: file.name, + }, + child: file.name, + }); + + const uploadElemName = $e({ + tag: 'a', + attrs: { + className: 'eeprom-widget-file-name', + target: '_blank', + }, + child: uploadElemNameValue, + }); + + const uploadElemProgressText = $e({ + attrs: { + className: 'eeprom-widget-file-progress', + }, + child: 'Please wait...', + }); + + const uploadElemProgressBarValue = $e({ + attrs: { + className: 'eeprom-widget-file-bar-fill', + style: { + width: '0%', + }, + }, + }); + + const uploadElem = $e({ + attrs: { + className: 'eeprom-widget-file', + }, + child: [ + { + attrs: { + className: 'eeprom-widget-file-info', + }, + child: [ + uploadElemName, + uploadElemProgressText, + ], + }, + { + attrs: { + className: 'eeprom-widget-file-bar', + }, + child: uploadElemProgressBarValue, + }, + ], + }); + + if(eepromHistory.children.length > 0) + $ib(eepromHistory.firstChild, uploadElem); + else + eepromHistory.appendChild(uploadElem); + + const explodeUploadElem = function() { + $r(uploadElem); + }; + + const uploadTask = eepromClient.createUpload(file); + + uploadTask.onProgress = function(progressInfo) { + const progressValue = progressInfo.progress.toString() + '%'; + uploadElemProgressBarValue.style.width = progressValue; + uploadElemProgressText.textContent = progressValue + ' (' + (progressInfo.total - progressInfo.loaded).toString() + ' 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 _t = ['bytes', 'KB', 'MB', 'GB', 'TB'], + _i = parseInt(Math.floor(Math.log(errorInfo.maxSize) / Math.log(1024))), + _s = Math.round(errorInfo.maxSize / Math.pow(1024, _i), 2); + + errorText = 'Upload may not be larger than %1 %2.'.replace('%1', _s).replace('%2', _t[_i]); + } + break; + } + + uploadElem.classList.add('eeprom-widget-file-fail'); + uploadElemProgressText.textContent = errorText; + Misuzu.showMessageBox(errorText, 'Upload Error'); + } + }; + + uploadTask.onComplete = function(fileInfo) { + const parserMode = parseInt(postingParser.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 + ')'; + } + + uploadElem.classList.add('eeprom-widget-file-done'); + uploadElemName.href = fileInfo.url; + uploadElemProgressText.textContent = ''; + + const insertTheLinkIntoTheBoxEx2 = function() { + // should be more intelligent than just ploinking a space in front + $insertTags(postingText, ' ' + insertText, ''); + postingText.value = postingText.value.trim(); + }; + + uploadElemProgressText.appendChild($e({ + tag: 'a', + attrs: { + href: 'javascript:void(0);', + onclick: function() { insertTheLinkIntoTheBoxEx2(); }, + }, + child: 'Insert', + })); + uploadElemProgressText.appendChild($t(' ')); + uploadElemProgressText.appendChild($e({ + tag: 'a', + attrs: { + href: 'javascript:void(0);', + onclick: function() { + eepromClient.deleteUpload(fileInfo).start(); + explodeUploadElem(); + }, + }, + child: 'Delete', + })); + + insertTheLinkIntoTheBoxEx2(); + }; + + uploadTask.start(); + }; + + const eepromFormInput = $e({ + tag: 'input', + attrs: { + type: 'file', + multiple: 'multiple', + className: 'eeprom-widget-form-input', + onchange: function(ev) { + const files = this.files; + for(const file of files) + eepromHandleFileUpload(file); + this.value = ''; + }, + }, + }); + + const eepromForm = $e({ + tag: 'label', + attrs: { + className: 'eeprom-widget-form', + }, + child: [ + eepromFormInput, + { + attrs: { + className: 'eeprom-widget-form-text', + }, + child: 'Select Files...', + } + ], + }); + + const eepromWidget = $e({ + attrs: { + className: 'eeprom-widget', + }, + child: [ + eepromForm, + { + attrs: { + className: 'eeprom-widget-history', + }, + child: eepromHistory, + }, + ], + }); + postingForm.appendChild(eepromWidget); + + postingText.addEventListener('paste', function(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', function(ev) { + ev.preventDefault(); + ev.stopPropagation(); + }); + document.body.addEventListener('dragover', function(ev) { + ev.preventDefault(); + ev.stopPropagation(); + }); + document.body.addEventListener('dragleave', function(ev) { + ev.preventDefault(); + ev.stopPropagation(); + }); + document.body.addEventListener('drop', function(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); + } + }); + }, + onerror: function(ev) { + console.error('Failed to initialise EEPROM: ', ev); + }, + }, + })); + // hack: don't prompt user when hitting submit, really need to make this not stupid. postingButtons.firstElementChild.addEventListener('click', function() { Misuzu.Forum.Editor.allowWindowClose = true; diff --git a/misuzu.php b/misuzu.php index aaf1fcf..54f240e 100644 --- a/misuzu.php +++ b/misuzu.php @@ -154,6 +154,10 @@ Template::set('globals', [ 'site_url' => $cfg->getValue('site.url', IConfig::T_STR), 'site_twitter' => $cfg->getValue('social.twitter', IConfig::T_STR), 'site_chat' => $cfg->getValue('sockChat.chatPath.normal', IConfig::T_STR), + 'eeprom' => [ + 'path' => $cfg->getValue('eeprom.path', IConfig::T_STR), + 'app' => $cfg->getValue('eeprom.app', IConfig::T_STR), + ], ]); Template::addPath(MSZ_TEMPLATES); diff --git a/templates/forum/posting.twig b/templates/forum/posting.twig index 699990d..b859ae1 100644 --- a/templates/forum/posting.twig +++ b/templates/forum/posting.twig @@ -8,7 +8,7 @@ {% set is_opening = not is_reply or posting_post.is_opening_post|default(false) %} {% block content %} -
+ {{ input_hidden('post[' ~ (is_reply ? 'topic' : 'forum') ~ ']', is_reply ? posting_topic.topic_id : posting_forum.forum_id) }} {{ input_hidden('post[mode]', posting_mode) }} {{ input_csrf() }} @@ -43,7 +43,7 @@ {% endif %} -
+
+ + {% if globals.eeprom.path is not empty %} + + {% endif %} {% endblock %}