Worked on #5
This commit is contained in:
parent
885b2cf31f
commit
3fd34db37c
15 changed files with 454 additions and 5 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
||||||
local.ini
|
local.ini
|
||||||
db.sqlite
|
db.sqlite
|
||||||
db.sqlite-journal
|
db.sqlite-journal
|
||||||
|
public_html/media/js/jquery.tagit.js
|
||||||
|
public_html/media/css/jquery.tagit.css
|
||||||
|
|
|
@ -4,6 +4,7 @@ prettyPrint=1
|
||||||
|
|
||||||
[main]
|
[main]
|
||||||
dbPath=./db.sqlite
|
dbPath=./db.sqlite
|
||||||
|
filesPath=./files/
|
||||||
title=szurubooru
|
title=szurubooru
|
||||||
|
|
||||||
[registration]
|
[registration]
|
||||||
|
|
2
files/.gitignore
vendored
Normal file
2
files/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
11
init.php
Normal file
11
init.php
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
function download($source, $destination)
|
||||||
|
{
|
||||||
|
$content = file_get_contents($source);
|
||||||
|
if (substr($destination, -1, 1) == '/')
|
||||||
|
$destination .= basename($source);
|
||||||
|
file_put_contents($destination, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
download('http://raw.github.com/aehlke/tag-it/master/css/jquery.tagit.css', './public_html/media/css/jquery.tagit.css');
|
||||||
|
download('http://raw.github.com/aehlke/tag-it/master/js/tag-it.min.js', './public_html/media/js/jquery.tagit.js');
|
|
@ -3,7 +3,7 @@ body {
|
||||||
color: black;
|
color: black;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-family: sans-serif;
|
font-family: 'Droid Sans', sans-serif;
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,3 +77,19 @@ nav li.search input {
|
||||||
.clear {
|
.clear {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sidebar {
|
||||||
|
float: left;
|
||||||
|
width: 25%;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar h1 {
|
||||||
|
margin-top: 0;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-content {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
110
public_html/media/css/upload.css
Normal file
110
public_html/media/css/upload.css
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
.items .item {
|
||||||
|
width: 30%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items .sep {
|
||||||
|
width: 3%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#file-handler-wrapper {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#file-handler {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 150%;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 200px;
|
||||||
|
width: 100%;
|
||||||
|
display: table-cell;
|
||||||
|
border: 3px dashed #eee;
|
||||||
|
}
|
||||||
|
#file-handler.active {
|
||||||
|
background: #eee;
|
||||||
|
border-color: firebrick;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post .thumbnail {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
line-height: 100px;
|
||||||
|
background-image: url('../img/thumb-unavailable.png');
|
||||||
|
border: 1px solid black;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#post-template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post {
|
||||||
|
margin-bottom: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post .remove-trigger {
|
||||||
|
cursor: pointer;
|
||||||
|
float: right;
|
||||||
|
color: rgba(128, 0, 0, 0.25);
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.post .remove-trigger span {
|
||||||
|
margin-left: 0.25em;
|
||||||
|
vertical-align: middle;
|
||||||
|
color: rgba(128, 0, 0, 1);
|
||||||
|
font-size: 130%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post label {
|
||||||
|
line-height: 33px;
|
||||||
|
}
|
||||||
|
.post label.left {
|
||||||
|
display: inline-block;
|
||||||
|
width: 4em;
|
||||||
|
}
|
||||||
|
.post .safety label:not(.left) {
|
||||||
|
margin-right: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post .file-name strong {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.safety-sfw {
|
||||||
|
color: #63ca63;
|
||||||
|
}
|
||||||
|
.safety-sketchy {
|
||||||
|
color: #f4c657;
|
||||||
|
}
|
||||||
|
.safety-nsfw {
|
||||||
|
color: #df4b0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tagit {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-wrapper {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
input.submit {
|
||||||
|
margin: 0 auto;
|
||||||
|
font-size: 115%;
|
||||||
|
padding: 0.2em 0.7em;
|
||||||
|
color: white;
|
||||||
|
background: cornflowerblue;
|
||||||
|
border: 0;
|
||||||
|
}
|
BIN
public_html/media/img/pixel.gif
Normal file
BIN
public_html/media/img/pixel.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 67 B |
BIN
public_html/media/img/thumb-unavailable.png
Normal file
BIN
public_html/media/img/thumb-unavailable.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 688 B |
138
public_html/media/js/upload.js
Normal file
138
public_html/media/js/upload.js
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
$(function()
|
||||||
|
{
|
||||||
|
var handler = $('#file-handler');
|
||||||
|
var tags = []; //todo: retrieve tags
|
||||||
|
|
||||||
|
$('#upload-step2').hide();
|
||||||
|
|
||||||
|
handler.on('dragenter', function(e)
|
||||||
|
{
|
||||||
|
$(this).addClass('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on('dragleave', function(e)
|
||||||
|
{
|
||||||
|
$(this).removeClass('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on('dragover', function(e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on('drop', function(e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
handleFiles(e.originalEvent.dataTransfer.files);
|
||||||
|
$(this).trigger('dragleave');
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on('click', function(e)
|
||||||
|
{
|
||||||
|
$(':file').show().focus().trigger('click').hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(':file').change(function(e)
|
||||||
|
{
|
||||||
|
handleFiles(this.files);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.post .remove-trigger').on('click', function()
|
||||||
|
{
|
||||||
|
$(this).parents('.post').slideUp(function()
|
||||||
|
{
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$('#upload-step2 form').submit(function(e)
|
||||||
|
{
|
||||||
|
var url = $(this).attr('action') + '?json';
|
||||||
|
e.preventDefault();
|
||||||
|
var posts = $('.post', $(this));
|
||||||
|
|
||||||
|
if (posts.length == 0)
|
||||||
|
{
|
||||||
|
alert('No posts to upload!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
posts.each(function()
|
||||||
|
{
|
||||||
|
var postDom = $(this);
|
||||||
|
var file = postDom.data('file');
|
||||||
|
var tags = postDom.find('[name=tags]').val();
|
||||||
|
var safety = postDom.find('[name=safety]').val();
|
||||||
|
var fd = new FormData();
|
||||||
|
fd.append('file', file);
|
||||||
|
fd.append('tags', tags);
|
||||||
|
fd.append('safety', safety);
|
||||||
|
|
||||||
|
var ajax =
|
||||||
|
{
|
||||||
|
url: url,
|
||||||
|
data: fd,
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
type: 'POST',
|
||||||
|
success: function(data)
|
||||||
|
{
|
||||||
|
//todo: do this nice
|
||||||
|
if (data['success'])
|
||||||
|
{
|
||||||
|
postDom.slideUp();
|
||||||
|
//alert(file.name + ': success!');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alert(data['errorMessage']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.ajax(ajax);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleFiles(files)
|
||||||
|
{
|
||||||
|
$('#upload-step1').fadeOut(function()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < files.length; i ++)
|
||||||
|
{
|
||||||
|
var file = files[i];
|
||||||
|
var postDom = $('#post-template').clone(true);
|
||||||
|
postDom.removeAttr('id');
|
||||||
|
postDom.data('file', file);
|
||||||
|
$('.file-name strong', postDom).text(file.name);
|
||||||
|
$('.tags input', postDom).tagit({caseSensitive: true, availableTags: tags, placeholderText: $('.tags input').attr('placeholder')});
|
||||||
|
$('.posts').append(postDom);
|
||||||
|
|
||||||
|
if (!file.type.match('image.*'))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = (function(theFile)
|
||||||
|
{
|
||||||
|
return function(e)
|
||||||
|
{
|
||||||
|
var img = postDom.find('img')
|
||||||
|
/*img.css('max-width', img.css('width'));
|
||||||
|
img.css('max-height', img.css('height'));
|
||||||
|
img.css('width', 'auto');
|
||||||
|
img.css('height', 'auto');*/
|
||||||
|
img.css('background-image', 'none');
|
||||||
|
img.attr('src', e.target.result);
|
||||||
|
};
|
||||||
|
})(file);
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
$('#upload-step2').fadeIn(function()
|
||||||
|
{
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -29,6 +29,7 @@ class Bootstrap
|
||||||
|
|
||||||
$this->context->title = $this->config->main->title;
|
$this->context->title = $this->config->main->title;
|
||||||
$this->context->stylesheets = ['core.css'];
|
$this->context->stylesheets = ['core.css'];
|
||||||
|
$this->context->scripts = [];
|
||||||
|
|
||||||
$this->context->layoutName = isset($_GET['json'])
|
$this->context->layoutName = isset($_GET['json'])
|
||||||
? 'layout-json'
|
? 'layout-json'
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
class PostController
|
class PostController
|
||||||
{
|
{
|
||||||
|
public function workWrapper($callback)
|
||||||
|
{
|
||||||
|
$this->context->stylesheets []= 'jquery.tagit.css';
|
||||||
|
$this->context->scripts []= 'jquery.tagit.js';
|
||||||
|
$callback();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @route /posts
|
* @route /posts
|
||||||
* @route /posts/{query}
|
* @route /posts/{query}
|
||||||
|
@ -27,8 +34,78 @@ class PostController
|
||||||
*/
|
*/
|
||||||
public function uploadAction()
|
public function uploadAction()
|
||||||
{
|
{
|
||||||
|
$this->context->stylesheets []= 'upload.css';
|
||||||
|
$this->context->scripts []= 'upload.js';
|
||||||
$this->context->subTitle = 'upload';
|
$this->context->subTitle = 'upload';
|
||||||
throw new Exception('Not implemented');
|
|
||||||
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::UploadPost);
|
||||||
|
|
||||||
|
if (isset($_FILES['file']))
|
||||||
|
{
|
||||||
|
$suppliedSafety = intval(InputHelper::get('safety'));
|
||||||
|
if (!in_array($suppliedSafety, PostSafety::getAll()))
|
||||||
|
throw new SimpleException('Invalid safety type "' . $suppliedSafety . '"');
|
||||||
|
|
||||||
|
$suppliedTags = InputHelper::get('tags');
|
||||||
|
$suppliedTags = preg_split('/[,;\s+]/', $suppliedTags);
|
||||||
|
$suppliedTags = array_filter($suppliedTags);
|
||||||
|
$suppliedTags = array_unique($suppliedTags);
|
||||||
|
foreach ($suppliedTags as $tag)
|
||||||
|
if (!preg_match('/^\w+$/i', $tag))
|
||||||
|
throw new SimpleException('Invalid tag "' . $tag . '"');
|
||||||
|
|
||||||
|
$suppliedFile = $_FILES['file'];
|
||||||
|
|
||||||
|
switch ($suppliedFile['type'])
|
||||||
|
{
|
||||||
|
case 'image/gif':
|
||||||
|
case 'image/png':
|
||||||
|
case 'image/jpeg':
|
||||||
|
$postType = PostType::Image;
|
||||||
|
break;
|
||||||
|
case 'application/x-shockwave-flash':
|
||||||
|
$postType = PostType::Flash;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new SimpleException('Invalid file type "' . $suppliedFile['type'] . '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo: find out duplicate files
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
$name = md5(mt_rand() . uniqid());
|
||||||
|
$path = $this->config->main->filesPath . DIRECTORY_SEPARATOR . $name;
|
||||||
|
}
|
||||||
|
while (file_exists($path));
|
||||||
|
|
||||||
|
$dbTags = [];
|
||||||
|
foreach ($suppliedTags as $tag)
|
||||||
|
{
|
||||||
|
$dbTag = R::findOne('tag', 'name = ?', [$tag]);
|
||||||
|
if (!$dbTag)
|
||||||
|
{
|
||||||
|
$dbTag = R::dispense('tag');
|
||||||
|
$dbTag->name = $tag;
|
||||||
|
R::store($dbTag);
|
||||||
|
}
|
||||||
|
$dbTags []= $dbTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbPost = R::dispense('post');
|
||||||
|
$dbPost->type = $postType;
|
||||||
|
$dbPost->name = $name;
|
||||||
|
$dbPost->mimeType = $suppliedFile['type'];
|
||||||
|
$dbPost->safety = $suppliedSafety;
|
||||||
|
$dbPost->sharedTag = $dbTags;
|
||||||
|
|
||||||
|
move_uploaded_file($suppliedFile['tmp_name'], $path);
|
||||||
|
R::store($dbPost);
|
||||||
|
|
||||||
|
//todo: generate thumbnail
|
||||||
|
|
||||||
|
$this->context->transport->success = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
12
src/Models/PostSafety.php
Normal file
12
src/Models/PostSafety.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
class PostSafety
|
||||||
|
{
|
||||||
|
const Safe = 1;
|
||||||
|
const Sketchy = 2;
|
||||||
|
const Unsafe = 3;
|
||||||
|
|
||||||
|
public static function getAll()
|
||||||
|
{
|
||||||
|
return [self::Safe, self::Sketchy, self::Unsafe];
|
||||||
|
}
|
||||||
|
}
|
6
src/Models/PostType.php
Normal file
6
src/Models/PostType.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
class PostType
|
||||||
|
{
|
||||||
|
const Image = 1;
|
||||||
|
const Flash = 2;
|
||||||
|
}
|
|
@ -10,7 +10,13 @@
|
||||||
<?php foreach ($this->context->stylesheets as $name): ?>
|
<?php foreach ($this->context->stylesheets as $name): ?>
|
||||||
<link rel="stylesheet" type="text/css" href="<?php echo \Chibi\UrlHelper::absoluteUrl('/media/css/' . $name) ?>"/>
|
<link rel="stylesheet" type="text/css" href="<?php echo \Chibi\UrlHelper::absoluteUrl('/media/css/' . $name) ?>"/>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans:400,700">
|
||||||
|
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/flick/jquery-ui.css">
|
||||||
|
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||||
|
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.min.js"></script>
|
||||||
|
<?php foreach ($this->context->scripts as $name): ?>
|
||||||
|
<script type="text/javascript" src="<?php echo \Chibi\UrlHelper::absoluteUrl('/media/js/' . $name) ?>"></script>
|
||||||
|
<?php endforeach ?>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
67
src/Views/post-upload.phtml
Normal file
67
src/Views/post-upload.phtml
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?php if ($this->context->transport->success === true): ?>
|
||||||
|
<p>Post created!</p>
|
||||||
|
<?php elseif (isset($this->context->transport->errorMessage)): ?>
|
||||||
|
<p class="alert alert-error"><?php echo $this->context->transport->errorMessage ?></p>
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<div id="sidebar">
|
||||||
|
<h1>file upload</h1>
|
||||||
|
<p>Use tags to describe uploaded images. Try to specify characters, their look and shows they are from.</p>
|
||||||
|
<p>Set proper visibility setting if the image isn’t safe for work or you’re not sure it’s 100% <span class="safety-sfw">safe</span>.</p>
|
||||||
|
<p>Only registered users can view <span class="safety-sketchy">sketchy</span> or <span class="safety-nsfw">NSFW</span> content.</p>
|
||||||
|
<p>Click submit when you’re done.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="inner-content">
|
||||||
|
<div id="upload-step1">
|
||||||
|
<input type=file multiple style="display: none"/>
|
||||||
|
<div id="file-handler-wrapper">
|
||||||
|
<div id="file-handler">
|
||||||
|
Drop files here!<br>
|
||||||
|
Or just click on this box.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="upload-step2">
|
||||||
|
<form action="<?php echo \Chibi\UrlHelper::route('post', 'upload') ?>" method="post">
|
||||||
|
<div class="posts">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="submit-wrapper">
|
||||||
|
<input type="submit" value="Submit" class="submit btn"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="post-template" class="post">
|
||||||
|
<a class="remove-trigger">
|
||||||
|
remove <span>×</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<img class="thumbnail" src="<?php echo \Chibi\UrlHelper::absoluteUrl('/media/img/pixel.gif') ?>" alt="Thumbnail"/>
|
||||||
|
<div>
|
||||||
|
<div class="file-name">
|
||||||
|
<label class="left">File:</label>
|
||||||
|
<strong>filename.jpg</strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="safety">
|
||||||
|
<label class="left">Safety:</label>
|
||||||
|
<label><input type="radio" name="safety" value="<?php echo PostSafety::Safe ?>" checked="checked"/> Safe for work</label>
|
||||||
|
<label><input type="radio" name="safety" value="<?php echo PostSafety::Sketchy ?>"/> Sketchy</label>
|
||||||
|
<label><input type="radio" name="safety" value="<?php echo PostSafety::Unsafe ?>"/> Not safe for work</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tags">
|
||||||
|
<label class="left">Tags:</label>
|
||||||
|
<input type="text" name="tags" placeholder="enter some tags…"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php endif ?>
|
Loading…
Reference in a new issue