Worked on post uploads (#11) - added GUI
This commit is contained in:
parent
7ec3715cdd
commit
dfb1198143
8 changed files with 1047 additions and 4 deletions
|
@ -32,3 +32,12 @@ a {
|
||||||
a:hover {
|
a:hover {
|
||||||
color: #7b3;
|
color: #7b3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin: 1.5em auto;
|
||||||
|
height: 1px;
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
display: table-row;
|
display: table-row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
width: 1%;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
.form-label,
|
.form-label,
|
||||||
.form-input {
|
.form-input {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
|
@ -25,6 +30,7 @@
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag-input,
|
||||||
textarea,
|
textarea,
|
||||||
input[type=text],
|
input[type=text],
|
||||||
input[type=password] {
|
input[type=password] {
|
||||||
|
@ -45,7 +51,22 @@ input[type=button] {
|
||||||
background: #eee;
|
background: #eee;
|
||||||
font-family: 'Droid Sans', sans-serif;
|
font-family: 'Droid Sans', sans-serif;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
button:hover,
|
||||||
|
input[type=button]:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.highlight,
|
||||||
|
input[type=button].highlight {
|
||||||
|
background: #ad5;
|
||||||
|
}
|
||||||
|
button:hover.highlight,
|
||||||
|
input[type=button]:hover.highlight {
|
||||||
|
background: #dfa;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.file-handler {
|
.file-handler {
|
||||||
border: 3px dashed #eee;
|
border: 3px dashed #eee;
|
||||||
|
@ -58,3 +79,32 @@ input[type=button] {
|
||||||
border-color: #6a2;
|
border-color: #6a2;
|
||||||
background-color: #eeffcc;
|
background-color: #eeffcc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag-input {
|
||||||
|
padding: 1px;
|
||||||
|
line-height: normal !important;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
.tag-input ul {
|
||||||
|
list-style-type: none;
|
||||||
|
display: inline;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.tag-input li {
|
||||||
|
background: #ddd;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 1px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.tag-input input {
|
||||||
|
border: none;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.tag-input li a {
|
||||||
|
color: black;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
167
public_html/css/post-upload.css
Normal file
167
public_html/css/post-upload.css
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#post-upload-step1 {
|
||||||
|
display: table;
|
||||||
|
width: 30em;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#post-upload-step1 .file-handler {
|
||||||
|
padding: 3.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#post-upload-step1 .url-handler {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#post-upload-step1 .url-handler .input-wrapper {
|
||||||
|
margin-right: 8.5em;
|
||||||
|
}
|
||||||
|
#post-upload-step1 .url-handler button {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#post-upload-step2 .hybrid-view {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
@media all and (min-width: 62.5em) {
|
||||||
|
#post-upload-step2 .hybrid-window:first-child {
|
||||||
|
width: 40%;
|
||||||
|
margin-right: 1em;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
#post-upload-step2 .hybrid-window:last-child {
|
||||||
|
display: inline-block;
|
||||||
|
width: 57.5%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#post-upload-step2 .thumbnail img {
|
||||||
|
border: 1px solid black;
|
||||||
|
vertical-align: middle;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#post-upload-step2 table {
|
||||||
|
border-spacing: 0;
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table td,
|
||||||
|
#post-upload-step2 table th {
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table th {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table tr.selected {
|
||||||
|
background: #faffca;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table .checkbox {
|
||||||
|
width: 30px;
|
||||||
|
padding: 0.2em 0;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table .checkbox input {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table .thumbnail {
|
||||||
|
width: 40px;
|
||||||
|
padding: 0.2em 0;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table .safety {
|
||||||
|
width: 60px;
|
||||||
|
padding: 0.2em 0;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table .tags {
|
||||||
|
text-align: left;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table .safety {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table .safety [class^=safety-] {
|
||||||
|
box-shadow: inset 0 0 0 3px rgba(0,0,0,0.1);
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
#post-upload-step2 table .safety-safe { background: #b2efa2; }
|
||||||
|
#post-upload-step2 table .safety-sketchy { background: #f0e4a8; }
|
||||||
|
#post-upload-step2 table .safety-unsafe { background: #fbc6b6; }
|
||||||
|
#post-upload-step2 table .thumbnail img {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
display: inline-block;
|
||||||
|
background-size: 30px 30px;
|
||||||
|
}
|
||||||
|
#post-upload-step2 .operations {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#post-upload-step2 .operations li {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0.3em 0.3em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#post-upload-step2 form {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
#post-upload-step2 .messages {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
#post-upload-step2 .form-slider {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#post-upload-step2 .form-slider .thumbnail img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 300px;
|
||||||
|
margin: 0 auto 1em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#post-upload-step2,
|
||||||
|
.template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#lightbox {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
#lightbox img {
|
||||||
|
max-width: 400px;
|
||||||
|
max-height: 400px;
|
||||||
|
background: white;
|
||||||
|
border: 0.5em solid white;
|
||||||
|
box-shadow: 0 0 0 1px #eee;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#lightbox:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: -8px;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -8px;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background: white;
|
||||||
|
border-left: 1px solid #eee;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#uploading-alert {
|
||||||
|
display: none;
|
||||||
|
text-align: left;
|
||||||
|
}
|
|
@ -13,6 +13,7 @@
|
||||||
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
||||||
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
|
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
|
||||||
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/mousetrap/1.4.6/mousetrap.min.js"></script>
|
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/mousetrap/1.4.6/mousetrap.min.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css"/>
|
||||||
<!-- build:template
|
<!-- build:template
|
||||||
<link rel="stylesheet" type="text/css" href="app.min.css?<%= timestamp %>"/>
|
<link rel="stylesheet" type="text/css" href="app.min.css?<%= timestamp %>"/>
|
||||||
/build -->
|
/build -->
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
<link rel="stylesheet" type="text/css" href="/css/pager.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/pager.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/login-form.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/login-form.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/registration-form.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/registration-form.css"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/post-upload.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/user-list.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/user-list.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/user.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/user.css"/>
|
||||||
<!-- /build -->
|
<!-- /build -->
|
||||||
|
@ -59,6 +61,7 @@
|
||||||
<script type="text/javascript" src="/js/Util.js"></script>
|
<script type="text/javascript" src="/js/Util.js"></script>
|
||||||
<script type="text/javascript" src="/js/BrowsingSettings.js"></script>
|
<script type="text/javascript" src="/js/BrowsingSettings.js"></script>
|
||||||
<script type="text/javascript" src="/js/Controls/FileDropper.js"></script>
|
<script type="text/javascript" src="/js/Controls/FileDropper.js"></script>
|
||||||
|
<script type="text/javascript" src="/js/Controls/TagInput.js"></script>
|
||||||
<script type="text/javascript" src="/js/PresenterManager.js"></script>
|
<script type="text/javascript" src="/js/PresenterManager.js"></script>
|
||||||
<script type="text/javascript" src="/js/Presenters/TopNavigationPresenter.js"></script>
|
<script type="text/javascript" src="/js/Presenters/TopNavigationPresenter.js"></script>
|
||||||
<script type="text/javascript" src="/js/Presenters/PagedCollectionPresenter.js"></script>
|
<script type="text/javascript" src="/js/Presenters/PagedCollectionPresenter.js"></script>
|
||||||
|
|
140
public_html/js/Controls/TagInput.js
Normal file
140
public_html/js/Controls/TagInput.js
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
var App = App || {};
|
||||||
|
App.Controls = App.Controls || {};
|
||||||
|
|
||||||
|
//todo: autocomplete
|
||||||
|
|
||||||
|
App.Controls.TagInput = function(
|
||||||
|
$underlyingInput,
|
||||||
|
_,
|
||||||
|
jQuery) {
|
||||||
|
|
||||||
|
var KEY_RETURN = 13;
|
||||||
|
var KEY_SPACE = 32;
|
||||||
|
var KEY_BACKSPACE = 8;
|
||||||
|
|
||||||
|
var tags = [];
|
||||||
|
var options = {
|
||||||
|
beforeTagAdded: null,
|
||||||
|
beforeTagRemoved: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($underlyingInput.length !== 1) {
|
||||||
|
throw new Error('Cannot set tag input to more than one elements at once');
|
||||||
|
}
|
||||||
|
if ($underlyingInput.attr('data-tagged')) {
|
||||||
|
throw new Error('Tag input was already initialized for this element');
|
||||||
|
}
|
||||||
|
$underlyingInput.attr('data-tagged', true);
|
||||||
|
$underlyingInput.hide();
|
||||||
|
|
||||||
|
var $wrapper = jQuery('<div class="tag-input">');
|
||||||
|
var $tagList = jQuery('<ul class="tags">');
|
||||||
|
var $input = jQuery('<input type="text"/>');
|
||||||
|
$wrapper.append($tagList);
|
||||||
|
$wrapper.append($input);
|
||||||
|
$wrapper.insertAfter($underlyingInput);
|
||||||
|
$wrapper.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$input.focus();
|
||||||
|
});
|
||||||
|
$input.attr('placeholder', $underlyingInput.attr('placeholder'));
|
||||||
|
|
||||||
|
$input.unbind('paste').bind('paste', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var pastedText;
|
||||||
|
if (window.clipboardData) {
|
||||||
|
pastedText = window.clipboardData.getData('Text');
|
||||||
|
} else {
|
||||||
|
pastedText = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||||
|
}
|
||||||
|
var patedTags = pastedText.split(/\s+/);
|
||||||
|
_.each(patedTags, function(tag) {
|
||||||
|
addTag(tag);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.unbind('keydown').bind('keydown', function(e) {
|
||||||
|
if (e.which === KEY_RETURN || e.which === KEY_SPACE) {
|
||||||
|
e.preventDefault();
|
||||||
|
var tag = $input.val();
|
||||||
|
addTag(tag);
|
||||||
|
$input.val('');
|
||||||
|
} else if (e.which === KEY_BACKSPACE && jQuery(this).val().length === 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
removeLastTag();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function addTag(tag) {
|
||||||
|
tag = tag.trim();
|
||||||
|
if (tag.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var oldTags = getTags();
|
||||||
|
if (_.contains(_.map(oldTags, function(tag) { return tag.toLowerCase(); }), tag.toLowerCase())) {
|
||||||
|
flashTag(tag);
|
||||||
|
} else {
|
||||||
|
if (typeof(options.beforeTagAdded) === 'function') {
|
||||||
|
options.beforeTagAdded(tag);
|
||||||
|
}
|
||||||
|
var newTags = oldTags.slice();
|
||||||
|
newTags.push(tag);
|
||||||
|
setTags(newTags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeTag(tag) {
|
||||||
|
var oldTags = getTags();
|
||||||
|
var newTags = _.without(oldTags, tag);
|
||||||
|
if (newTags.length !== oldTags.length) {
|
||||||
|
if (typeof(options.beforeTagRemoved) === 'function') {
|
||||||
|
options.beforeTagRemoved(tag);
|
||||||
|
}
|
||||||
|
setTags(newTags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeLastTag() {
|
||||||
|
removeTag(_.last(getTags()));
|
||||||
|
}
|
||||||
|
|
||||||
|
function flashTag(tag) {
|
||||||
|
var $elem = $tagList.find('li[data-tag="' + tag.toLowerCase() + '"]');
|
||||||
|
$elem.css({backgroundColor: 'rgba(255, 200, 200, 1)'});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTags(newTags) {
|
||||||
|
tags = newTags.slice();
|
||||||
|
$tagList.empty();
|
||||||
|
$underlyingInput.val(newTags.join(' '));
|
||||||
|
_.each(newTags, function(tag) {
|
||||||
|
var $elem = jQuery('<li/>');
|
||||||
|
$elem.text(tag);
|
||||||
|
$elem.attr('data-tag', tag.toLowerCase());
|
||||||
|
|
||||||
|
var $deleteButton = jQuery('<a><i class="fa fa-remove"></i></a>');
|
||||||
|
$deleteButton.bind('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
removeTag(tag);
|
||||||
|
$input.focus();
|
||||||
|
});
|
||||||
|
$elem.append($deleteButton);
|
||||||
|
|
||||||
|
$tagList.append($elem);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(options, {
|
||||||
|
setTags: setTags,
|
||||||
|
getTags: getTags,
|
||||||
|
removeTag: removeTag,
|
||||||
|
addTag: addTag,
|
||||||
|
});
|
||||||
|
return options;
|
||||||
|
};
|
||||||
|
|
||||||
|
App.DI.register('tagInput', App.Controls.TagInput);
|
|
@ -2,19 +2,547 @@ var App = App || {};
|
||||||
App.Presenters = App.Presenters || {};
|
App.Presenters = App.Presenters || {};
|
||||||
|
|
||||||
App.Presenters.PostUploadPresenter = function(
|
App.Presenters.PostUploadPresenter = function(
|
||||||
|
_,
|
||||||
jQuery,
|
jQuery,
|
||||||
topNavigationPresenter) {
|
mousetrap,
|
||||||
|
promise,
|
||||||
|
util,
|
||||||
|
api,
|
||||||
|
router,
|
||||||
|
topNavigationPresenter,
|
||||||
|
messagePresenter) {
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
|
var $messages;
|
||||||
|
var template;
|
||||||
|
var allPosts = [];
|
||||||
|
var tagInput;
|
||||||
|
var interactionEnabled = true;
|
||||||
|
|
||||||
function init(args) {
|
function init(args) {
|
||||||
topNavigationPresenter.select('upload');
|
topNavigationPresenter.select('upload');
|
||||||
topNavigationPresenter.changeTitle('Upload');
|
topNavigationPresenter.changeTitle('Upload');
|
||||||
|
|
||||||
|
promise.wait(util.promiseTemplate('post-upload')).then(function(html) {
|
||||||
|
template = _.template(html);
|
||||||
render();
|
render();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function 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 {
|
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);
|
||||||
|
|
|
@ -4,6 +4,16 @@ App.Util = function(_, jQuery, promise) {
|
||||||
|
|
||||||
var templateCache = {};
|
var templateCache = {};
|
||||||
|
|
||||||
|
function enableExitConfirmation() {
|
||||||
|
jQuery(window).bind('beforeunload', function(e) {
|
||||||
|
return 'There are unsaved changes.';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableExitConfirmation() {
|
||||||
|
jQuery(window).unbind('beforeunload');
|
||||||
|
}
|
||||||
|
|
||||||
function parseComplexRouteArgs(args) {
|
function parseComplexRouteArgs(args) {
|
||||||
var result = {};
|
var result = {};
|
||||||
args = (args || '').split(/;/);
|
args = (args || '').split(/;/);
|
||||||
|
@ -136,6 +146,8 @@ App.Util = function(_, jQuery, promise) {
|
||||||
parseComplexRouteArgs: parseComplexRouteArgs,
|
parseComplexRouteArgs: parseComplexRouteArgs,
|
||||||
compileComplexRouteArgs: compileComplexRouteArgs,
|
compileComplexRouteArgs: compileComplexRouteArgs,
|
||||||
formatRelativeTime: formatRelativeTime,
|
formatRelativeTime: formatRelativeTime,
|
||||||
|
enableExitConfirmation: enableExitConfirmation,
|
||||||
|
disableExitConfirmation: disableExitConfirmation,
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
134
public_html/templates/post-upload.tpl
Normal file
134
public_html/templates/post-upload.tpl
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
<div id="post-upload-step1">
|
||||||
|
<input name="post-content" multiple type="file"/>
|
||||||
|
|
||||||
|
<div class="url-handler">
|
||||||
|
<div class="input-wrapper">
|
||||||
|
<input type="text" placeholder="Alternatively, paste an URL here." name="url"/>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Add URL</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="post-upload-step2">
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="hybrid-view">
|
||||||
|
<div class="hybrid-window">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="checkbox">
|
||||||
|
<input type="checkbox" name="select-all"/>
|
||||||
|
</th>
|
||||||
|
<th class="thumbnail"></th>
|
||||||
|
<th class="tags">Tags</th>
|
||||||
|
<th class="safety">Safety</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
<tfoot>
|
||||||
|
<tr class="template">
|
||||||
|
<td class="checkbox">
|
||||||
|
<input type="checkbox"/>
|
||||||
|
</td>
|
||||||
|
<td class="thumbnail">
|
||||||
|
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="Thumbnail"/>
|
||||||
|
</td>
|
||||||
|
<td class="tags"></td>
|
||||||
|
<td class="safety"><div class="safety-template"></div></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<ul class="operations"><!--
|
||||||
|
--><li>
|
||||||
|
<button class="remove"><i class="fa fa-remove"></i> Remove</button>
|
||||||
|
</li><!--
|
||||||
|
--><li>
|
||||||
|
<button class="move-up"><i class="fa fa-chevron-up"></i> Move up</button>
|
||||||
|
</li><!--
|
||||||
|
--><li>
|
||||||
|
<button class="move-down"><i class="fa fa-chevron-down"></i> Move down</button>
|
||||||
|
</li><!--
|
||||||
|
--><li class="right">
|
||||||
|
<button class="submit highlight" type="submit"><i class="fa fa-upload"></i> Submit</button>
|
||||||
|
</li><!--
|
||||||
|
--></ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hybrid-window">
|
||||||
|
<div class="messages"></div>
|
||||||
|
|
||||||
|
<div class="form-slider">
|
||||||
|
<div class="thumbnail">
|
||||||
|
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="Thumbnail"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form class="form-wrapper">
|
||||||
|
<div class="form-row file-name">
|
||||||
|
<label class="form-label">File:</label>
|
||||||
|
<div class="form-input">
|
||||||
|
<strong>filename.jpg</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label">Safety:</label>
|
||||||
|
<div class="form-input">
|
||||||
|
<label for="post-safety-safe">
|
||||||
|
<input type="radio" id="post-safety-safe" name="safety" value="safe"/>
|
||||||
|
Safe
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="post-safety-sketchy">
|
||||||
|
<input type="radio" id="post-safety-sketchy" name="safety" value="sketchy"/>
|
||||||
|
Sketchy
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="post-safety-unsafe">
|
||||||
|
<input type="radio" id="post-safety-unsafe" name="safety" value="unsafe"/>
|
||||||
|
Unsafe
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label" for="post-tags">Tags:</label>
|
||||||
|
<div class="form-input">
|
||||||
|
<input type="text" name="tags" id="post-tags" placeholder="Enter some tags…" value=""/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label" for="post-source">Source:</label>
|
||||||
|
<div class="form-input">
|
||||||
|
<input maxlength="200" type="text" name="source" id="post-source" placeholder="Where did you get this? (optional)" value=""/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label" for="post-anonymous">Anonymity:</label>
|
||||||
|
<div class="form-input">
|
||||||
|
<label for="post-anonymous">
|
||||||
|
<input type="checkbox" id="post-anonymous" name="anonymous"/>
|
||||||
|
Don't show my name in this post
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="lightbox">
|
||||||
|
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="Preview">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
Loading…
Reference in a new issue