forked from GithubBackups/vichan
Merge pull request #428 from marktaiwan/post-form
Feature: drag and drop file selector
This commit is contained in:
commit
5c976ea689
182
js/file-selector.js
Normal file
182
js/file-selector.js
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* file-selector.js - Add support for drag and drop file selection, and paste from clipbboard on supported browsers.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* $config['additional_javascript'][] = 'js/jquery.min.js';
|
||||||
|
* $config['additional_javascript'][] = 'js/file-selector.js';
|
||||||
|
*/
|
||||||
|
function init_file_selector() {
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
// add options panel item
|
||||||
|
if (window.Options && Options.get_tab('general')) {
|
||||||
|
Options.extend_tab('general', '<label id="file-drag-drop"><input type="checkbox">' + _('Drag and drop file selection') + '</label>');
|
||||||
|
|
||||||
|
$('#file-drag-drop>input').on('click', function() {
|
||||||
|
if ($('#file-drag-drop>input').is(':checked')) {
|
||||||
|
localStorage.file_dragdrop = 'true';
|
||||||
|
} else {
|
||||||
|
localStorage.file_dragdrop = 'false';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (localStorage.file_dragdrop === 'undefined') localStorage.file_dragdrop = 'true';
|
||||||
|
if (localStorage.file_dragdrop === 'true') $('#file-drag-drop>input').prop('checked', true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// disabled by user, or incompatible browser.
|
||||||
|
if (localStorage.file_dragdrop == 'false' || !(window.FileReader && window.File))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// multipost not enabled
|
||||||
|
if (typeof max_images == 'undefined') {
|
||||||
|
var max_images = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var files = [];
|
||||||
|
$('#upload_file').hide(); // hide the original file selector
|
||||||
|
$('.dropzone-wrap').css('user-select', 'none').show(); // let jquery add browser specific prefix
|
||||||
|
|
||||||
|
function addFile(file) {
|
||||||
|
if (files.length == max_images)
|
||||||
|
return;
|
||||||
|
|
||||||
|
files.push(file);
|
||||||
|
addThumb(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFile(file) {
|
||||||
|
files.splice(files.indexOf(file), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getThumbElement(file) {
|
||||||
|
return $('.tmb-container').filter(function(){return($(this).data('file-ref')==file);});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addThumb(file) {
|
||||||
|
|
||||||
|
var fileName = (file.name.length < 24) ? file.name : file.name.substr(0, 22) + '…';
|
||||||
|
var fileType = file.type.split('/')[0];
|
||||||
|
var fileExt = file.type.split('/')[1];
|
||||||
|
var $fileThumb;
|
||||||
|
|
||||||
|
$('.file-thumbs').append($('<div>')
|
||||||
|
.addClass('tmb-container')
|
||||||
|
.data('file-ref', file)
|
||||||
|
.append(
|
||||||
|
$('<div>').addClass('remove-btn').html('✖'),
|
||||||
|
$('<div>').addClass('file-tmb'),
|
||||||
|
$('<div>').addClass('tmb-filename').html(fileName)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fileType == 'image') {
|
||||||
|
// if image file, generate thumbnail
|
||||||
|
var reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onloadend = function () {
|
||||||
|
var dataURL = reader.result;
|
||||||
|
var $fileThumb = getThumbElement(file).find('.file-tmb');
|
||||||
|
$fileThumb.css('background-image', 'url('+ dataURL +')');
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
} else {
|
||||||
|
$fileThumb = getThumbElement(file).find('.file-tmb');
|
||||||
|
$fileThumb.html('<span>' + fileExt.toUpperCase() + '</span>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on('ajax_before_post', function (e, formData) {
|
||||||
|
for (var i=0; i<max_images; i++) {
|
||||||
|
var key = 'file';
|
||||||
|
if (i > 0) key += i + 1;
|
||||||
|
formData.append(key, files[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// clear file queue and UI on success
|
||||||
|
$(document).on('ajax_after_post', function () {
|
||||||
|
files = [];
|
||||||
|
$('.file-thumbs').empty();
|
||||||
|
});
|
||||||
|
|
||||||
|
var dragCounter = 0;
|
||||||
|
var dropHandlers = {
|
||||||
|
dragenter: function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (dragCounter === 0) $(this).addClass('dragover');
|
||||||
|
dragCounter++;
|
||||||
|
},
|
||||||
|
dragover: function (e) {
|
||||||
|
// needed for webkit to work
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
},
|
||||||
|
dragleave: function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
dragCounter--;
|
||||||
|
if (dragCounter === 0) $(this).removeClass('dragover');
|
||||||
|
},
|
||||||
|
drop: function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
$(this).removeClass('dragover');
|
||||||
|
dragCounter = 0;
|
||||||
|
|
||||||
|
var fileList = e.originalEvent.dataTransfer.files;
|
||||||
|
for (var i=0; i<fileList.length; i++) {
|
||||||
|
addFile(fileList[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// attach handlers
|
||||||
|
$(document).on(dropHandlers, '.dropzone');
|
||||||
|
|
||||||
|
$(document).on('click', '.dropzone .remove-btn', function (e) {
|
||||||
|
var file = $(e.target).parent().data('file-ref');
|
||||||
|
|
||||||
|
removeFile(file);
|
||||||
|
$(e.target).parent().remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('click', '.dropzone .file-hint', function (e) {
|
||||||
|
var $fileSelector = $('<input type="file" multiple>');
|
||||||
|
|
||||||
|
$fileSelector.on('change', function (e) {
|
||||||
|
if (this.files.length > 0) {
|
||||||
|
for (var i=0; i<this.files.length; i++) {
|
||||||
|
addFile(this.files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
$fileSelector.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('paste', function (e) {
|
||||||
|
var clipboard = e.originalEvent.clipboardData;
|
||||||
|
if (typeof clipboard.items != 'undefined' && clipboard.items.length != 0) {
|
||||||
|
|
||||||
|
//Webkit
|
||||||
|
for (var i=0; i<clipboard.items.length; i++) {
|
||||||
|
if (clipboard.items[i].kind != 'file')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//convert blob to file
|
||||||
|
var file = new File([clipboard.items[i].getAsFile()], 'ClipboardImage.png', {type: 'image/png'});
|
||||||
|
addFile(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
@ -1181,3 +1181,81 @@ div.mix {
|
|||||||
#youtube-size input {
|
#youtube-size input {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* File selector */
|
||||||
|
.dropzone {
|
||||||
|
color: #000;
|
||||||
|
cursor: default;
|
||||||
|
margin: auto;
|
||||||
|
padding: 0px 4px;
|
||||||
|
text-align: center;
|
||||||
|
min-height: 50px;
|
||||||
|
max-height: 140px;
|
||||||
|
transition: 0.2s;
|
||||||
|
background-color: rgba(200, 200, 200, 0.5);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.dropzone-wrap {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.dropzone .file-hint {
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
padding: 10px 0px;
|
||||||
|
top: 5px;
|
||||||
|
transition: 0.2s;
|
||||||
|
border: 2px dashed rgba(125, 125, 125, 0.4);
|
||||||
|
}
|
||||||
|
.file-hint:hover, .dropzone.dragover .file-hint {
|
||||||
|
color: rgba(0, 0, 0, 1);
|
||||||
|
border-color: rgba(125, 125, 125, 0.8);
|
||||||
|
}
|
||||||
|
.dropzone.dragover {
|
||||||
|
background-color: rgba(200, 200, 200, 1);
|
||||||
|
}
|
||||||
|
.dropzone .file-thumbs {
|
||||||
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.dropzone .tmb-container {
|
||||||
|
padding: 3px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.dropzone .file-tmb {
|
||||||
|
height: 40px;
|
||||||
|
width: 70px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
background-color: rgba(187, 187, 187, 0.5);
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
.dropzone .file-tmb span {
|
||||||
|
font-weight: 600;
|
||||||
|
position: relative;
|
||||||
|
top: 13px;
|
||||||
|
}
|
||||||
|
.dropzone .tmb-filename {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: bottom;
|
||||||
|
bottom: 12px;
|
||||||
|
position: relative;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.dropzone .remove-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
color: rgba(125, 125, 125, 0.5);
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: bottom;
|
||||||
|
bottom: 10px;
|
||||||
|
position: relative;
|
||||||
|
margin-right: 5px;
|
||||||
|
font-size: 20px
|
||||||
|
}
|
||||||
|
.dropzone .remove-btn:hover {
|
||||||
|
color: rgba(125, 125, 125, 1);
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<input type="hidden" name="page" value="{{ current_page }}">
|
<input type="hidden" name="page" value="{{ current_page }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if mod %}<input type="hidden" name="mod" value="1">{% endif %}
|
{% if mod %}<input type="hidden" name="mod" value="1">{% endif %}
|
||||||
<table class="post-table">
|
<table class="post-table"><tbody>
|
||||||
{% if not config.field_disable_name or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}<tr>
|
{% if not config.field_disable_name or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}<tr>
|
||||||
<th>
|
<th>
|
||||||
{% trans %}Name{% endtrans %}
|
{% trans %}Name{% endtrans %}
|
||||||
@ -91,6 +91,13 @@
|
|||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="file" name="file" id="upload_file">
|
<input type="file" name="file" id="upload_file">
|
||||||
|
<div class="dropzone-wrap" style="display: none;">
|
||||||
|
<div class="dropzone">
|
||||||
|
<div class="file-hint">Select/drop/paste files here</div>
|
||||||
|
<div class="file-thumbs"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">init_file_selector();</script>
|
||||||
{% if config.allow_upload_by_url %}
|
{% if config.allow_upload_by_url %}
|
||||||
<div style="float:none;text-align:left" id="upload_url">
|
<div style="float:none;text-align:left" id="upload_url">
|
||||||
<label for="file_url">{% trans %}Or URL{% endtrans %}</label>:
|
<label for="file_url">{% trans %}Or URL{% endtrans %}</label>:
|
||||||
@ -129,7 +136,8 @@
|
|||||||
<strong class="faq-message unimportant hint"><br />Confused? See the <a href="/faq.html">FAQ</a>.</strong>
|
<strong class="faq-message unimportant hint"><br />Confused? See the <a href="/faq.html">FAQ</a>.</strong>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody></table><table class="post-table-options"><tbody>
|
</tbody></table>
|
||||||
|
<table class="post-table-options"><tbody>
|
||||||
|
|
||||||
{% if not config.force_flag %}
|
{% if not config.force_flag %}
|
||||||
{{ flag_tr }}
|
{{ flag_tr }}
|
||||||
@ -163,17 +171,23 @@
|
|||||||
<td>
|
<td>
|
||||||
<div class="no-bump-option">
|
<div class="no-bump-option">
|
||||||
<label><input title="No bump" id="no-bump" name="no-bump" type="checkbox">
|
<label><input title="No bump" id="no-bump" name="no-bump" type="checkbox">
|
||||||
{% trans %}Do not bump{% endtrans %} <span class="unimportant hint">{% trans %}(you can also write sage in the email field){% endtrans %}</span></label>
|
{% trans %}Do not bump{% endtrans %}
|
||||||
|
<br/>
|
||||||
|
<span class="unimportant hint">{% trans %}(you can also write sage in the email field){% endtrans %}</span></label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if config.spoiler_images %}<div class="spoiler-images-option">
|
{% if config.spoiler_images %}<div class="spoiler-images-option">
|
||||||
<label><input title="Spoiler images" id="spoiler" name="spoiler" type="checkbox">
|
<label><input title="Spoiler images" id="spoiler" name="spoiler" type="checkbox">
|
||||||
{% trans %}Spoiler images{% endtrans %} <span class="unimportant hint">{% trans %}(this replaces the thumbnails of your images with question marks){% endtrans %}</label>
|
{% trans %}Spoiler images{% endtrans %}
|
||||||
|
<br/>
|
||||||
|
<span class="unimportant hint">{% trans %}(this replaces the thumbnails of your images with question marks){% endtrans %}</label>
|
||||||
</div>{% endif %}
|
</div>{% endif %}
|
||||||
|
|
||||||
{% if config.allow_no_country and config.country_flags and not config.force_flag %}<div class="no-country-option">
|
{% if config.allow_no_country and config.country_flags and not config.force_flag %}<div class="no-country-option">
|
||||||
<label><input title="No country flag" id="no_country" name="no_country" type="checkbox">
|
<label><input title="No country flag" id="no_country" name="no_country" type="checkbox">
|
||||||
{% trans %}Hide country{% endtrans %} <span class="unimportant hint">{% trans %}(this board displays your country when you post if this is unchecked){% endtrans %}</span></label>
|
{% trans %}Hide country{% endtrans %}
|
||||||
|
<br/>
|
||||||
|
<span class="unimportant hint">{% trans %}(this board displays your country when you post if this is unchecked){% endtrans %}</span></label>
|
||||||
</div>{% endif %}
|
</div>{% endif %}
|
||||||
|
|
||||||
{% if mod %}
|
{% if mod %}
|
||||||
@ -225,7 +239,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</tbody></table>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user