szurubooru/public_html/js/Presenters/PostUploadPresenter.js

563 lines
14 KiB
JavaScript
Raw Normal View History

2014-09-07 19:49:11 +02:00
var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.PostUploadPresenter = function(
_,
2014-09-07 19:49:11 +02:00
jQuery,
mousetrap,
promise,
util,
2014-09-15 11:38:24 +02:00
auth,
api,
router,
topNavigationPresenter,
messagePresenter) {
2014-09-07 19:49:11 +02:00
var $el = jQuery('#content');
var $messages;
var template;
var allPosts = [];
var tagInput;
var interactionEnabled = true;
2014-09-07 19:49:11 +02:00
function init(args) {
topNavigationPresenter.select('upload');
topNavigationPresenter.changeTitle('Upload');
promise.wait(util.promiseTemplate('post-upload')).then(function(html) {
template = _.template(html);
render();
});
2014-09-07 19:49:11 +02:00
}
function render() {
2014-09-15 11:38:24 +02:00
$el.html(template({
canUploadPostsAnonymously: auth.hasPrivilege(auth.privileges.uploadPostsAnonymously)
}));
$messages = $el.find('.messages');
tagInput = new App.Controls.TagInput($el.find('form [name=tags]'), _, jQuery);
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', simpleKeyPressed(selectPrevPostTableRow), 'keyup');
mousetrap.bind('d', simpleKeyPressed(selectNextPostTableRow), 'keyup');
$el.find('.remove').click(removeButtonClicked);
$el.find('.move-up').click(moveUpButtonClicked);
$el.find('.move-down').click(moveDownButtonClicked);
$el.find('.submit').click(submitButtonClicked);
}
function simpleKeyPressed(callback) {
return function(e) {
if (!e.altKey && !e.ctrlKey) {
callback();
}
};
}
function getDefaultPost() {
return {
safety: 'safe',
source: null,
anonymous: false,
tags: [],
2014-09-15 11:38:24 +02:00
fileName: null,
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);
createPostTableRow(post);
}
function postChanged(post) {
updatePostTableRow(post);
}
function createPostTableRow(post) {
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);
selectPostTableRow(post);
showOrHidePostsTable();
}
function updatePostTableRow(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);
2014-09-15 11:38:24 +02:00
tagInput.focus();
}
2014-09-15 11:38:24 +02:00
$el.find('.post-table-op').prop('disabled', selectedPosts.length === 0);
}
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();
2014-09-15 11:38:24 +02:00
$postEditForm.find('.file-name strong').text(post.fileName || post.url);
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);
}
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);
}
postChanged(post);
});
}
function postTableRowImageHovered(e) {
var $img = jQuery(this);
if ($img.attr('src')) {
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 selectPostTableRow(post) {
if (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 selectPrevPostTableRow() {
selectPostTableRow($el.find('tbody tr.selected:eq(0)').prev().data('post'));
}
function selectNextPostTableRow() {
selectPostTableRow($el.find('tbody tr.selected:eq(0)').next().data('post'));
}
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);
2014-09-15 11:38:24 +02:00
messagePresenter.showInfo($messages, 'Uploading in progress&hellip;');
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 {
2014-09-15 11:38:24 +02:00
formData.content = post.content;
formData.contentFileName = post.fileName;
}
formData.source = post.source;
formData.safety = post.safety;
2014-09-15 11:38:24 +02:00
formData.anonymous = (post.anonymous | 0);
formData.tags = post.tags.join(' ');
if (post.tags.length === 0) {
2014-09-15 11:38:24 +02:00
messagePresenter.hideMessages($messages);
messagePresenter.showError($messages, 'No tags set.');
interactionEnabled = true;
return;
}
promise.wait(api.post('/posts', formData)).then(function(response) {
$row.slideUp(function(response) {
$row.remove();
2014-09-15 11:38:24 +02:00
posts.shift();
setAllPosts(posts);
uploadNextPost();
});
}).fail(function(response) {
2014-09-15 11:38:24 +02:00
messagePresenter.hideMessages($messages);
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();
interactionEnabled = false;
uploadNextPost();
2014-09-08 22:02:28 +02:00
}
2014-09-07 19:49:11 +02:00
return {
init: init,
render: render,
};
};
2014-09-15 11:38:24 +02:00
App.DI.register('postUploadPresenter', ['_', 'jQuery', 'mousetrap', 'promise', 'util', 'auth', 'api', 'router', 'topNavigationPresenter', 'messagePresenter'], App.Presenters.PostUploadPresenter);