mirror of
https://github.com/rr-/szurubooru.git
synced 2025-07-17 08:26:24 +00:00
Worked on post uploads (#11) - added GUI
This commit is contained in:
@ -2,19 +2,547 @@ var App = App || {};
|
||||
App.Presenters = App.Presenters || {};
|
||||
|
||||
App.Presenters.PostUploadPresenter = function(
|
||||
_,
|
||||
jQuery,
|
||||
topNavigationPresenter) {
|
||||
mousetrap,
|
||||
promise,
|
||||
util,
|
||||
api,
|
||||
router,
|
||||
topNavigationPresenter,
|
||||
messagePresenter) {
|
||||
|
||||
var $el = jQuery('#content');
|
||||
var $messages;
|
||||
var template;
|
||||
var allPosts = [];
|
||||
var tagInput;
|
||||
var interactionEnabled = true;
|
||||
|
||||
function init(args) {
|
||||
topNavigationPresenter.select('upload');
|
||||
topNavigationPresenter.changeTitle('Upload');
|
||||
render();
|
||||
|
||||
promise.wait(util.promiseTemplate('post-upload')).then(function(html) {
|
||||
template = _.template(html);
|
||||
render();
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
$el.html('Post upload placeholder');
|
||||
$el.html(template());
|
||||
$messages = $el.find('.messages');
|
||||
|
||||
new App.Controls.FileDropper($el.find('[name=post-content]'), fileHandlerChanged, jQuery);
|
||||
$el.find('.url-handler input').keydown(urlHandlerKeyPressed);
|
||||
$el.find('.url-handler button').click(urlHandlerButtonClicked);
|
||||
$el.find('thead th.checkbox').click(postTableSelectAllCheckboxClicked);
|
||||
|
||||
mousetrap.bind('a', function(e) {
|
||||
if (!e.altKey && !e.ctrlKey) {
|
||||
selectPrevPostInTable();
|
||||
}
|
||||
}, 'keyup');
|
||||
mousetrap.bind('d', function(e) {
|
||||
if (!e.altKey && !e.ctrlKey) {
|
||||
selectNextPostInTable();
|
||||
}
|
||||
}, 'keyup');
|
||||
|
||||
$el.find('.remove').click(removeButtonClicked);
|
||||
$el.find('.move-up').click(moveUpButtonClicked);
|
||||
$el.find('.move-down').click(moveDownButtonClicked);
|
||||
$el.find('.submit').click(submitButtonClicked);
|
||||
|
||||
tagInput = new App.Controls.TagInput($el.find('form [name=tags]'), _, jQuery);
|
||||
}
|
||||
|
||||
function getDefaultPost() {
|
||||
return {
|
||||
safety: 'safe',
|
||||
source: null,
|
||||
fileName: null,
|
||||
anonymous: false,
|
||||
tags: [],
|
||||
|
||||
content: null,
|
||||
url: null,
|
||||
thumbnail: null,
|
||||
$tableRow: null,
|
||||
};
|
||||
}
|
||||
|
||||
function urlHandlerKeyPressed(e) {
|
||||
if (e.which !== 13) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
$el.find('.url-handler button').trigger('click');
|
||||
}
|
||||
|
||||
function urlHandlerButtonClicked(e) {
|
||||
var $input = $el.find('.url-handler input');
|
||||
|
||||
var url = $input.val().trim();
|
||||
if (url === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
var protocol = /^(\w+):\/\//.exec(url);
|
||||
if (!protocol) {
|
||||
url = 'http://' + url;
|
||||
} else {
|
||||
protocol = protocol[1].toLowerCase();
|
||||
if (protocol !== 'http' && protocol !== 'https') {
|
||||
window.alert('Unsupported protocol: ' + protocol);
|
||||
return;
|
||||
}
|
||||
}
|
||||
$input.val('');
|
||||
addPostFromUrl(url);
|
||||
}
|
||||
|
||||
function fileHandlerChanged(files) {
|
||||
for (var i = 0; i < files.length; i ++) {
|
||||
addPostFromFile(files[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function addPostFromFile(file) {
|
||||
var post = _.extend({}, getDefaultPost(), {fileName: file.name});
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
post.content = e.target.result;
|
||||
if (file.type.match('image.*')) {
|
||||
post.thumbnail = e.target.result;
|
||||
postThumbnailLoaded(post);
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
postAdded(post);
|
||||
}
|
||||
|
||||
function addPostFromUrl(url) {
|
||||
var post = _.extend({}, getDefaultPost(), {url: url, source: url, fileName: url});
|
||||
|
||||
var matches = url.match(/watch.*?=([a-zA-Z0-9_-]+)/);
|
||||
if (matches) {
|
||||
var youtubeThumbnailUrl = 'http://img.youtube.com/vi/' + matches[1] + '/mqdefault.jpg';
|
||||
post.thumbnail = youtubeThumbnailUrl;
|
||||
} else {
|
||||
post.thumbnail = url;
|
||||
}
|
||||
postAdded(post);
|
||||
postThumbnailLoaded(post);
|
||||
}
|
||||
|
||||
function postAdded(post) {
|
||||
var allPosts = getAllPosts();
|
||||
allPosts.push(post);
|
||||
setAllPosts(allPosts);
|
||||
|
||||
var $table = $el.find('table');
|
||||
var $row = $table.find('.template').clone(true);
|
||||
|
||||
post.$tableRow = $row;
|
||||
|
||||
$row.removeClass('template');
|
||||
$row.find('td:not(.checkbox)').click(postTableRowClicked);
|
||||
$row.find('td.checkbox').click(postTableCheckboxClicked);
|
||||
$row.find('img').mouseenter(postTableRowImageHovered);
|
||||
$row.find('img').mouseleave(postTableRowImageUnhovered);
|
||||
$row.data('post', post);
|
||||
$table.find('tbody').append($row);
|
||||
|
||||
postChanged(post);
|
||||
|
||||
selectPostInTable(post);
|
||||
showOrHidePostsTable();
|
||||
}
|
||||
|
||||
function postChanged(post) {
|
||||
var $row = post.$tableRow;
|
||||
$row.find('.tags').text(post.tags.join(', ') || '-');
|
||||
$row.find('.safety div').attr('class', 'safety-' + post.safety);
|
||||
}
|
||||
|
||||
function postThumbnailLoaded(post) {
|
||||
var selectedPosts = getSelectedPosts();
|
||||
if (selectedPosts.length === 1 && selectedPosts[0] === post && post.thumbnail !== null) {
|
||||
updatePostThumbnailInForm(post);
|
||||
}
|
||||
updatePostThumbnailInTable(post);
|
||||
}
|
||||
|
||||
function updatePostThumbnailInForm(post) {
|
||||
$el.find('.form-slider .thumbnail img')[0].setAttribute('src', post.thumbnail);
|
||||
}
|
||||
|
||||
function updatePostThumbnailInTable(post) {
|
||||
var $row = post.$tableRow;
|
||||
//huge speedup thanks to this condition
|
||||
if ($row.find('img').attr('src') !== post.thumbnail && post.thumbnail !== null) {
|
||||
$row.find('img')[0].setAttribute('src', post.thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
function postTableRowClicked(e) {
|
||||
e.preventDefault();
|
||||
var $allCheckboxes = jQuery(this).parents('table').find('tbody input[type=checkbox]');
|
||||
var $myCheckbox = jQuery(this).parents('tr').find('input[type=checkbox]');
|
||||
$allCheckboxes.prop('checked', false);
|
||||
$myCheckbox.prop('checked', true);
|
||||
postTableCheckboxesChanged(e);
|
||||
}
|
||||
|
||||
function postTableCheckboxClicked(e) {
|
||||
if (e.target.nodeName === 'TD') {
|
||||
var checkbox = jQuery(this).find('input[type=checkbox]');
|
||||
checkbox.prop('checked', !checkbox.prop('checked'));
|
||||
}
|
||||
postTableCheckboxesChanged(e);
|
||||
}
|
||||
|
||||
function postTableSelectAllCheckboxClicked(e) {
|
||||
var $checkbox = jQuery(this).find('input[type=checkbox]');
|
||||
if (e.target.nodeName === 'TH') {
|
||||
$checkbox.prop('checked', !$checkbox.prop('checked'));
|
||||
}
|
||||
$el.find('tbody input[type=checkbox]').prop('checked', $checkbox.prop('checked'));
|
||||
postTableCheckboxesChanged();
|
||||
}
|
||||
|
||||
function postTableCheckboxesChanged(e) {
|
||||
var $table = $el.find('table');
|
||||
if (!interactionEnabled) {
|
||||
if (typeof(e) !== 'undefined') {
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$table.find('tbody tr').each(function(i, row) {
|
||||
var $row = jQuery(row);
|
||||
var checked = $row.find('input[type=checkbox]').prop('checked');
|
||||
$row.toggleClass('selected', checked);
|
||||
});
|
||||
|
||||
var allPosts = getAllPosts();
|
||||
var selectedPosts = getSelectedPosts();
|
||||
$table.find('[name=select-all]').prop('checked', allPosts.length === selectedPosts.length);
|
||||
postTableSelectionChanged(selectedPosts);
|
||||
}
|
||||
|
||||
function getAllPosts() {
|
||||
return allPosts;
|
||||
}
|
||||
|
||||
function setAllPosts(newPosts) {
|
||||
allPosts = newPosts;
|
||||
}
|
||||
|
||||
function setAllPostsFromTable() {
|
||||
var newPosts = _.map($el.find('tbody tr'), function(row) {
|
||||
var $row = jQuery(row);
|
||||
return $row.data('post');
|
||||
});
|
||||
setAllPosts(newPosts);
|
||||
}
|
||||
|
||||
function getSelectedPosts() {
|
||||
var selectedPosts = [];
|
||||
$el.find('tbody tr.selected').each(function(i, row) {
|
||||
var $row = jQuery(row);
|
||||
selectedPosts.push($row.data('post'));
|
||||
});
|
||||
return selectedPosts;
|
||||
}
|
||||
|
||||
function postTableSelectionChanged(selectedPosts) {
|
||||
if (selectedPosts.length === 0) {
|
||||
hidePostEditForm();
|
||||
} else {
|
||||
showPostEditForm(selectedPosts);
|
||||
}
|
||||
}
|
||||
|
||||
function hidePostEditForm() {
|
||||
var $postEditForm = $el.find('form');
|
||||
$postEditForm.parent('.form-slider').slideUp(function() {
|
||||
$postEditForm.find('.thumbnail').hide();
|
||||
});
|
||||
}
|
||||
|
||||
function showPostEditForm(selectedPosts) {
|
||||
var $postEditForm = $el.find('form');
|
||||
$postEditForm.parent('.form-slider').slideDown();
|
||||
if (selectedPosts.length !== 1) {
|
||||
$postEditForm.parent('.form-slider').find('.thumbnail').slideUp();
|
||||
$postEditForm.find('.file-name strong').text('Multiple posts selected');
|
||||
} else {
|
||||
var post = selectedPosts[0];
|
||||
$postEditForm.parent('.form-slider').find('.thumbnail').slideDown();
|
||||
$postEditForm.find('.file-name strong').text(post.fileName);
|
||||
updatePostThumbnailInForm(post);
|
||||
}
|
||||
|
||||
var combinedPost = getCombinedPost(selectedPosts);
|
||||
|
||||
$postEditForm.find('[name=source]').val(combinedPost.source);
|
||||
$postEditForm.find('[name=anonymous]').prop('checked', combinedPost.anonymous);
|
||||
$postEditForm.find('[name=safety]').prop('checked', false);
|
||||
if (combinedPost.safety !== null) {
|
||||
$postEditForm.find('[name=safety][value=' + combinedPost.safety + ']').prop('checked', true);
|
||||
}
|
||||
tagInput.setTags(combinedPost.tags);
|
||||
|
||||
$postEditForm.find('[name=source]').unbind('change').bind('change', function(e) {
|
||||
setPostsSource(selectedPosts, jQuery(this).val());
|
||||
});
|
||||
$postEditForm.find('[name=safety]').unbind('change').bind('change', function(e) {
|
||||
setPostsSafety(selectedPosts, jQuery(this).val());
|
||||
});
|
||||
$postEditForm.find('[name=anonymous]').unbind('change').bind('change', function(e) {
|
||||
setPostsAnonymity(selectedPosts, jQuery(this).is(':checked'));
|
||||
});
|
||||
tagInput.beforeTagAdded = function(tag) {
|
||||
addTagToPosts(selectedPosts, tag);
|
||||
};
|
||||
tagInput.beforeTagRemoved = function(tag) {
|
||||
removeTagFromPosts(selectedPosts, tag);
|
||||
};
|
||||
}
|
||||
|
||||
function getCombinedPost(posts) {
|
||||
var combinedPost = _.extend({}, getDefaultPost());
|
||||
if (posts.length === 0) {
|
||||
return combinedPost;
|
||||
}
|
||||
_.extend(combinedPost, posts[0]);
|
||||
|
||||
var tagFilter = function(post) {
|
||||
return function(tag) {
|
||||
return post.tags.indexOf(tag) !== -1;
|
||||
};
|
||||
};
|
||||
|
||||
for (var i = 1; i < posts.length; i ++) {
|
||||
if (posts[i].safety !== posts[0].safety) {
|
||||
combinedPost.safety = null;
|
||||
}
|
||||
if (posts[i].anonymous !== posts[0].anonymous) {
|
||||
combinedPost.anonymous = null;
|
||||
}
|
||||
if (posts[i].source !== posts[0].source) {
|
||||
combinedPost.source = null;
|
||||
}
|
||||
combinedPost.tags = combinedPost.tags.filter(tagFilter(posts[i]));
|
||||
}
|
||||
|
||||
return combinedPost;
|
||||
}
|
||||
|
||||
function setPostsSource(posts, newSource) {
|
||||
_.each(posts, function(post) {
|
||||
//todo: take care of max source length
|
||||
post.source = newSource;
|
||||
postChanged(post);
|
||||
});
|
||||
}
|
||||
|
||||
function setPostsSafety(posts, newSafety) {
|
||||
_.each(posts, function(post) {
|
||||
post.safety = newSafety;
|
||||
postChanged(post);
|
||||
});
|
||||
}
|
||||
|
||||
function setPostsAnonymity(posts, isAnonymous) {
|
||||
_.each(posts, function(post) {
|
||||
post.anonymous = isAnonymous;
|
||||
postChanged(post);
|
||||
});
|
||||
}
|
||||
|
||||
function addTagToPosts(posts, tag) {
|
||||
jQuery.each(posts, function(i, post) {
|
||||
var index = post.tags.indexOf(tag);
|
||||
if (index === -1) {
|
||||
post.tags.push(tag);
|
||||
}
|
||||
});
|
||||
jQuery.each(posts, function(i, post) {
|
||||
postChanged(post);
|
||||
});
|
||||
}
|
||||
|
||||
function removeTagFromPosts(posts, tag) {
|
||||
jQuery.each(posts, function(i, post) {
|
||||
var index = post.tags.indexOf(tag);
|
||||
if (index !== -1) {
|
||||
post.tags.splice(index, 1);
|
||||
}
|
||||
});
|
||||
jQuery.each(posts, function(i, post) {
|
||||
postChanged(post);
|
||||
});
|
||||
}
|
||||
|
||||
function postTableRowImageHovered(e) {
|
||||
var $img = jQuery(this);
|
||||
if (!$img.attr('src')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $lightbox = jQuery('#lightbox');
|
||||
$lightbox.find('img').attr('src', $img.attr('src'));
|
||||
$lightbox
|
||||
.show()
|
||||
.css({
|
||||
left: ($img.position().left + $img.outerWidth()) + 'px',
|
||||
top: ($img.position().top + ($img.outerHeight() - $lightbox.outerHeight()) / 2) + 'px',
|
||||
});
|
||||
}
|
||||
|
||||
function postTableRowImageUnhovered(e) {
|
||||
var $lightbox = jQuery('#lightbox');
|
||||
$lightbox.hide();
|
||||
}
|
||||
|
||||
function selectPostInTable(post) {
|
||||
var $table = $el.find('table');
|
||||
$table.find('tbody input[type=checkbox]').prop('checked', false);
|
||||
$table.find('tbody tr').each(function(i, row) {
|
||||
var $row = jQuery(row);
|
||||
if (post === $row.data('post')) {
|
||||
$row.find('input[type=checkbox]').prop('checked', true);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
postTableCheckboxesChanged();
|
||||
}
|
||||
|
||||
function selectPrevPostInTable() {
|
||||
var prevPost = $el.find('tbody tr.selected:eq(0)').prev().data('post');
|
||||
if (prevPost) {
|
||||
selectPostInTable(prevPost);
|
||||
}
|
||||
}
|
||||
|
||||
function selectNextPostInTable() {
|
||||
var nextPost = $el.find('tbody tr.selected:eq(0)').next().data('post');
|
||||
if (nextPost) {
|
||||
selectPostInTable(nextPost);
|
||||
}
|
||||
}
|
||||
|
||||
function showOrHidePostsTable() {
|
||||
if (getAllPosts().length === 0) {
|
||||
util.disableExitConfirmation();
|
||||
$el.find('#post-upload-step2').fadeOut();
|
||||
} else {
|
||||
util.enableExitConfirmation();
|
||||
$el.find('#post-upload-step2').fadeIn();
|
||||
}
|
||||
}
|
||||
|
||||
function removeButtonClicked(e) {
|
||||
e.preventDefault();
|
||||
removePosts(getSelectedPosts());
|
||||
}
|
||||
|
||||
function moveUpButtonClicked(e) {
|
||||
e.preventDefault();
|
||||
movePostsUp(getSelectedPosts());
|
||||
}
|
||||
|
||||
function moveDownButtonClicked(e) {
|
||||
e.preventDefault();
|
||||
movePostsDown(getSelectedPosts());
|
||||
}
|
||||
|
||||
function removePosts(posts) {
|
||||
_.each(posts, function(post) {
|
||||
post.$tableRow.remove();
|
||||
});
|
||||
setAllPostsFromTable();
|
||||
showOrHidePostsTable();
|
||||
postTableCheckboxesChanged();
|
||||
}
|
||||
|
||||
function movePostsUp(posts) {
|
||||
_.each(posts, function(post) {
|
||||
var $row = post.$tableRow;
|
||||
$row.insertBefore($row.prev('tr:not(.selected)'));
|
||||
});
|
||||
setAllPostsFromTable();
|
||||
}
|
||||
|
||||
function movePostsDown(posts) {
|
||||
_.each(posts, function(post) {
|
||||
var $row = post.$tableRow;
|
||||
$row.insertAfter($row.next('tr:not(.selected)'));
|
||||
});
|
||||
setAllPostsFromTable();
|
||||
}
|
||||
|
||||
function uploadNextPost() {
|
||||
messagePresenter.hideMessages($messages);
|
||||
|
||||
var posts = getAllPosts();
|
||||
if (posts.length === 0) {
|
||||
util.disableExitConfirmation();
|
||||
router.navigate('#/posts');
|
||||
return;
|
||||
}
|
||||
|
||||
var post = posts[0];
|
||||
var $row = post.$tableRow;
|
||||
|
||||
var formData = {};
|
||||
if (post.url) {
|
||||
formData.url = post.url;
|
||||
} else {
|
||||
formData.file = post.content;
|
||||
}
|
||||
formData.source = post.source;
|
||||
formData.safety = post.safety;
|
||||
formData.anonymous = post.anonymous;
|
||||
formData.tags = post.tags.join(', ');
|
||||
|
||||
if (post.tags.length === 0) {
|
||||
messagePresenter.showError($messages, 'No tags set.');
|
||||
interactionEnabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
promise.wait(api.post('/posts', formData)).then(function(response) {
|
||||
$row.slideUp(function(response) {
|
||||
$row.remove();
|
||||
uploadNextPost();
|
||||
});
|
||||
}).fail(function(response) {
|
||||
messagePresenter.showError($messages, response.json && response.json.error || response);
|
||||
interactionEnabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
function submitButtonClicked(e) {
|
||||
e.preventDefault();
|
||||
if (!interactionEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$el.find('tbody input[type=checkbox]').prop('checked', false);
|
||||
postTableCheckboxesChanged();
|
||||
|
||||
messagePresenter.showInfo($messages, 'Uploading in progress…');
|
||||
interactionEnabled = false;
|
||||
uploadNextPost();
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
@ -24,4 +552,4 @@ App.Presenters.PostUploadPresenter = function(
|
||||
|
||||
};
|
||||
|
||||
App.DI.register('postUploadPresenter', ['jQuery', 'topNavigationPresenter'], App.Presenters.PostUploadPresenter);
|
||||
App.DI.register('postUploadPresenter', ['_', 'jQuery', 'mousetrap', 'promise', 'util', 'api', 'router', 'topNavigationPresenter', 'messagePresenter'], App.Presenters.PostUploadPresenter);
|
||||
|
Reference in New Issue
Block a user