Fully enabled Inline Images.
A little detail: the "Add image" button was moved to a new table row, so it stands out more. Known bugs/errors: - When cropping an animated GIF inline (with a secondary JPG inline), although the images are correctly cropped, an empty error is displayed.
This commit is contained in:
parent
3ca7ad5e94
commit
cf9cba40b6
164
app/controllers/InlineController.php
Executable file
164
app/controllers/InlineController.php
Executable file
@ -0,0 +1,164 @@
|
||||
<?php
|
||||
class InlineController extends ApplicationController
|
||||
{
|
||||
protected function filters()
|
||||
{
|
||||
return [
|
||||
'member_only' => ['only' => ['create', 'copy']]
|
||||
];
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
# If this user already has an inline with no images, use it.
|
||||
$inline = Inline::where("(SELECT count(*) FROM inline_images WHERE inline_images.inline_id = inlines.id) = 0 AND user_id = ?", current_user()->id)->first();
|
||||
|
||||
if (!$inline) {
|
||||
$inline = Inline::create(['user_id' => current_user()->id]);
|
||||
}
|
||||
|
||||
$this->redirectTo(['#edit', 'id' => $inline->id]);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$query = Inline::none();
|
||||
if (!current_user()->is_anonymous()) {
|
||||
$query->order('user_id = ' . current_user()->id . ' DESC');
|
||||
}
|
||||
$query->order('created_at desc');
|
||||
|
||||
$this->inlines = $query->paginate($this->page_number(), 20);
|
||||
|
||||
$this->respond_to_list('inlines');
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$inline = Inline::find($this->params()->id);
|
||||
|
||||
if (!current_user()->has_permission($inline)) {
|
||||
$this->access_denied();
|
||||
return;
|
||||
}
|
||||
|
||||
$inline->destroy();
|
||||
$this->respond_to_success('Image group deleted', '#index');
|
||||
}
|
||||
|
||||
public function addImage()
|
||||
{
|
||||
$inline = Inline::find($this->params()->id);
|
||||
|
||||
if (!current_user()->has_permission($inline)) {
|
||||
$this->access_denied();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->request()->isPost()) {
|
||||
$new_image = InlineImage::create(array_merge($this->params()->image ?: [], ['inline_id' => $inline->id, 'file' => $this->params()->files()->image['file']]));
|
||||
if ($new_image->errors()->any()) {
|
||||
$this->respond_to_error($new_image, ['#edit', 'id' => $inline->id]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->redirectTo(['#edit', 'id' => $inline->id]);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteImage()
|
||||
{
|
||||
$image = InlineImage::find($this->params()->id);
|
||||
|
||||
$inline = $image->inline;
|
||||
|
||||
if (!current_user()->has_permission($inline)) {
|
||||
$this->access_denied();
|
||||
return;
|
||||
}
|
||||
|
||||
$image->destroy();
|
||||
$this->redirectTo(['#edit', 'id' => $inline->id]);
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
$inline = Inline::find($this->params()->id);
|
||||
|
||||
if (!current_user()->has_permission($inline)) {
|
||||
$this->access_denied();
|
||||
return;
|
||||
}
|
||||
|
||||
$inline->updateAttributes($this->params()->inline);
|
||||
|
||||
$images = $this->params()->image ?: [];
|
||||
foreach ($images as $id => $p) {
|
||||
$image = InlineImage::where('id = ? AND inline_id = ?', $id, $inline->id)->first();
|
||||
if (isset($p['description'])) {
|
||||
$image->description = $p['description'];
|
||||
}
|
||||
if (isset($p['sequence'])) {
|
||||
$image->sequence = $p['sequence'];
|
||||
}
|
||||
if ($image->changedAttributes()) {
|
||||
$image->save();
|
||||
}
|
||||
}
|
||||
|
||||
$inline->reload();
|
||||
$inline->renumber_sequences();
|
||||
|
||||
$this->notice('Image updated');
|
||||
$this->redirectTo(['#edit', 'id' => $inline->id]);
|
||||
}
|
||||
|
||||
# Create a copy of an inline image and all of its images. Allow copying from images
|
||||
# owned by someone else.
|
||||
public function copy()
|
||||
{
|
||||
$inline = Inline::find($this->params()->id);
|
||||
|
||||
$new_inline = Inline::create([
|
||||
'user_id' => current_user()->id,
|
||||
'description' => $inline->description
|
||||
]);
|
||||
|
||||
foreach ($inline->inline_images as $image) {
|
||||
$new_attributes = array_merge($image->attributes(), ['inline_id' => $new_inline->id]);
|
||||
unset($new_attributes['id']);
|
||||
$new_image = InlineImage::create($new_attributes);
|
||||
}
|
||||
|
||||
$this->respond_to_success('Image copied', ['#edit', 'id' => $new_inline->id]);
|
||||
}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
$this->inline = Inline::find($this->params()->id);
|
||||
}
|
||||
|
||||
public function crop()
|
||||
{
|
||||
$this->inline = Inline::find($this->params()->id);
|
||||
$image = $this->inline->inline_images->toArray();
|
||||
$this->image = array_shift($image);
|
||||
if (!$this->image) {
|
||||
throw new Rails\ActiveRecord\Exception\RecordNotFoundException(
|
||||
"Inline images set #" . $this->inline->id . " doesn't have inline images"
|
||||
);
|
||||
}
|
||||
if (!current_user()->has_permission($this->inline)) {
|
||||
$this->access_denied();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->request()->isPost()) {
|
||||
if ($this->inline->crop($this->params()->toArray())) {
|
||||
$this->redirectTo(['#edit', 'id' => $this->inline->id]);
|
||||
} else {
|
||||
$this->respond_to_error($this->inline, ['#edit', 'id' => $this->inline->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -91,7 +91,12 @@ class ApplicationHelper extends Rails\ActionView\Helper
|
||||
if (!$inline->inline_images)
|
||||
return "";
|
||||
|
||||
$url = $inline->inline_images->first->preview_url();
|
||||
if ($inline->inline_images->any()) {
|
||||
$url = $inline->inline_images[0]->preview_url();
|
||||
} else {
|
||||
$url = '';
|
||||
}
|
||||
|
||||
if (!$preview_html)
|
||||
$preview_html = '<img src="'.$url.'">';
|
||||
|
||||
@ -108,29 +113,30 @@ class ApplicationHelper extends Rails\ActionView\Helper
|
||||
</div>
|
||||
';
|
||||
$inline_id = "inline-$id-$num";
|
||||
$script = 'InlineImage.register("'.$inline_id.'", '.to_json($inline).');';
|
||||
$script = 'InlineImage.register("' . $inline_id . '", ' . $inline->toJson() . ');';
|
||||
return array($block, $script, $inline_id);
|
||||
}
|
||||
|
||||
public function format_inlines($text, $id)
|
||||
{
|
||||
$num = 0;
|
||||
$num = 0;
|
||||
$list = [];
|
||||
|
||||
// preg_match('/image #(\d+)/i', $text, $m);
|
||||
// foreach ($m as $t) {
|
||||
// $i = Inline::find($m[1]);
|
||||
// if ($i) {
|
||||
// list($block, $script) = format_inline($i, $num, $id);
|
||||
// $list[] = $script;
|
||||
// $num++;
|
||||
// return $block;
|
||||
// } else
|
||||
// return $t;
|
||||
// }
|
||||
$text = preg_replace_callback('/image #(\d+)/i', function($m) use (&$list, &$num, $id) {
|
||||
$i = Inline::where(['id' => (int)$m[1]])->first();
|
||||
if ($i) {
|
||||
list($block, $script) = $this->format_inline($i, $num, $id);
|
||||
$list[] = $script;
|
||||
$num++;
|
||||
return $block;
|
||||
} else {
|
||||
return $m[0];
|
||||
}
|
||||
}, $text);
|
||||
|
||||
if ($num > 0 )
|
||||
$text .= '<script language="javascript">' . implode("\n", $list) . '</script>';
|
||||
if ($num > 0) {
|
||||
$text .= '<script type="text/javascript">' . implode("\n", $list) . '</script>';
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
18
app/helpers/InlineHelper.php
Executable file
18
app/helpers/InlineHelper.php
Executable file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
class InlineHelper extends Rails\ActionView\Helper
|
||||
{
|
||||
public function inline_image_tag($image, array $options = [], array $tag_options = [])
|
||||
{
|
||||
if (!empty($options['user_sample']) && $image->has_sample()) {
|
||||
$url = $image->sample_url();
|
||||
$tag_options['width'] = $image->sample_width();
|
||||
$tag_options['height'] = $image->sample_height();
|
||||
} else {
|
||||
$url = $image->file_url();
|
||||
$tag_options['width'] = $image->width;
|
||||
$tag_options['height'] = $image->height;
|
||||
}
|
||||
|
||||
return $this->imageTag($url, $tag_options);
|
||||
}
|
||||
}
|
@ -1,18 +1,34 @@
|
||||
<?php
|
||||
class Inline extends Rails\ActiveRecord\Base
|
||||
{
|
||||
protected function assotiacions()
|
||||
protected function associations()
|
||||
{
|
||||
return [
|
||||
'belongs_to' => [
|
||||
'user'
|
||||
],
|
||||
'has_many' => [
|
||||
'inline_images' => [function() { $this->order('sequence'); }, 'dependent' => 'destroy', 'class_name' => 'inlineImage']
|
||||
'inline_images' => [function() { $this->order('sequence'); } /*Not yet supported: 'dependent' => 'destroy'*/, 'class_name' => 'InlineImage']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
protected function callbacks()
|
||||
{
|
||||
return [
|
||||
'before_destroy' => [
|
||||
'destroy_inline_images'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
protected function destroy_inline_images()
|
||||
{
|
||||
foreach ($this->inline_images as $i) {
|
||||
$i->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
# Sequence numbers must start at 1 and increase monotonically, to keep the UI simple.
|
||||
# If we've been given sequences with gaps or duplicates, sanitize them.
|
||||
public function renumber_sequences()
|
||||
@ -65,7 +81,7 @@ class Inline extends Rails\ActiveRecord\Base
|
||||
|
||||
try {
|
||||
# Create one crop for the image, and InlineImage will create the sample and preview from that.
|
||||
Moebooru\Reizer::resize($image->file_ext, $image->file_path(), $new_image->tempfile_image_path(), $size, 95);
|
||||
Moebooru\Resizer::resize($image->file_ext, $image->file_path(), $new_image->tempfile_image_path(), $size, 95);
|
||||
chmod($new_image->tempfile_image_path(), 0775);
|
||||
} catch (Exception $e) {
|
||||
if (is_file($new_image->tempfile_image_path())) {
|
||||
@ -85,10 +101,10 @@ class Inline extends Rails\ActiveRecord\Base
|
||||
public function api_attributes()
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'description' => $this->description,
|
||||
'user_id' => $this->user_id,
|
||||
'images' => $this->inline_images->toArray()
|
||||
'id' => (int)$this->id,
|
||||
'description' => (string)$this->description,
|
||||
'user_id' => (int)$this->user_id,
|
||||
'images' => $this->inline_images->asJson()
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
*/
|
||||
class InlineImage extends Rails\ActiveRecord\Base
|
||||
{
|
||||
use Moebooru\TempfilePrefix;
|
||||
|
||||
public $source;
|
||||
|
||||
public $received_file;
|
||||
@ -64,17 +66,17 @@ class InlineImage extends Rails\ActiveRecord\Base
|
||||
|
||||
public function tempfile_image_path()
|
||||
{
|
||||
return $this->temfile_prefix . '.upload';
|
||||
return $this->tempfile_prefix() . '.upload';
|
||||
}
|
||||
|
||||
public function tempfile_sample_path()
|
||||
{
|
||||
return $this->temfile_prefix . '-sample.upload';
|
||||
return $this->tempfile_prefix() . '-sample.upload';
|
||||
}
|
||||
|
||||
public function tempfile_preview_path()
|
||||
{
|
||||
return $this->temfile_prefix . '-preview.upload';
|
||||
return $this->tempfile_prefix() . '-preview.upload';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,15 +104,15 @@ class InlineImage extends Rails\ActiveRecord\Base
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $f
|
||||
* @param Rails\ActionDispatch\Http\UploadedFile $f
|
||||
*/
|
||||
public function setFile($f)
|
||||
{
|
||||
if (!is_file($f) || !filesize($f)) {
|
||||
if (!$f->size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
copy($f, $this->tempfile_image_path());
|
||||
copy($f->tempName(), $this->tempfile_image_path());
|
||||
|
||||
$this->got_file();
|
||||
}
|
||||
@ -143,7 +145,7 @@ class InlineImage extends Rails\ActiveRecord\Base
|
||||
}
|
||||
|
||||
if (!file_exists($this->tempfile_image_path())) {
|
||||
$this->errors()->add('base', "No file received");
|
||||
$this->errors()->addToBase("No file received");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -156,7 +158,7 @@ class InlineImage extends Rails\ActiveRecord\Base
|
||||
}
|
||||
|
||||
if (!in_array($this->file_ext, ['jpg', 'png', 'gif'])) {
|
||||
$this->errors()->add('file', 'is an invalid content type: ' . $this->file_ext);
|
||||
$this->errors()->add('file', 'is an invalid content type: ' . $this->file_ext ?: 'unknown');
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -191,8 +193,10 @@ class InlineImage extends Rails\ActiveRecord\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
# We can generate the sample image during upload or offline. Use tempfile_image_path
|
||||
# if it exists, otherwise use file_path.
|
||||
/**
|
||||
* We can generate the sample image during upload or offline. Use tempfile_image_path
|
||||
* if it exists, otherwise use file_path.
|
||||
*/
|
||||
$path = $this->tempfile_image_path();
|
||||
if (!is_file($path)) {
|
||||
$path = $this->file_path();
|
||||
@ -263,8 +267,8 @@ class InlineImage extends Rails\ActiveRecord\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_dir(dirname($file_path))) {
|
||||
mkdir(dirname($file_path), 0777, true);
|
||||
if (!is_dir(dirname($this->file_path()))) {
|
||||
mkdir(dirname($this->file_path()), 0777, true);
|
||||
}
|
||||
rename($this->tempfile_image_path(), $this->file_path());
|
||||
|
||||
@ -290,7 +294,7 @@ class InlineImage extends Rails\ActiveRecord\Base
|
||||
return;
|
||||
}
|
||||
$siblings = $this->inline->inline_images;
|
||||
$max_sequence = max($siblings->getAttributes('sequence')) ?: 0;
|
||||
$max_sequence = ($siblings->getAttributes('sequence') && max($siblings->getAttributes('sequence'))) ?: 0;
|
||||
$this->sequence = $max_sequence + 1;
|
||||
}
|
||||
|
||||
@ -390,19 +394,19 @@ class InlineImage extends Rails\ActiveRecord\Base
|
||||
public function api_attributes()
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'sequence' => $this->sequence,
|
||||
'md5' => $this->md5,
|
||||
'width' => $this->width,
|
||||
'height' => $this->height,
|
||||
'sample_width' => $this->sample_width,
|
||||
'sample_height' => $this->sample_height,
|
||||
'preview_width' => $this->preview_dimensions()['width'],
|
||||
'id' => (int)$this->id,
|
||||
'sequence' => $this->sequence,
|
||||
'md5' => $this->md5,
|
||||
'width' => (int)$this->width,
|
||||
'height' => (int)$this->height,
|
||||
'sample_width' => $this->sample_width,
|
||||
'sample_height' => $this->sample_height,
|
||||
'preview_width' => $this->preview_dimensions()['width'],
|
||||
'preview_height' => $this->preview_dimensions()['height'],
|
||||
'description' => $this->description,
|
||||
'file_url' => $this->file_url(),
|
||||
'sample_url' => $this->sample_url(),
|
||||
'preview_url' => $this->preview_url()
|
||||
'description' => (string)$this->description,
|
||||
'file_url' => $this->file_url(),
|
||||
'sample_url' => $this->sample_url(),
|
||||
'preview_url' => $this->preview_url()
|
||||
];
|
||||
}
|
||||
|
||||
|
5
app/views/inline/_footer.php
Executable file
5
app/views/inline/_footer.php
Executable file
@ -0,0 +1,5 @@
|
||||
<?php $this->contentFor('subnavbar', function(){ ?>
|
||||
<li><?= $this->linkTo($this->t('.list'), ['action' => "index"]) ?></li>
|
||||
<?= $this->content('footer') ?>
|
||||
<!-- <li><?= $this->linkTo($this->t('.help'), ['controller' => "help", 'action' => "inlines"]) ?></li> -->
|
||||
<?php }) ?>
|
50
app/views/inline/crop.php
Executable file
50
app/views/inline/crop.php
Executable file
@ -0,0 +1,50 @@
|
||||
<div id="set-avatar" class="page">
|
||||
<?= $this->t('.crop_avatar') ?>
|
||||
<p>
|
||||
|
||||
<div class="avatar-crop">
|
||||
<?= $this->inline_image_tag($this->image, ['use_sample' => true], ['id' => "image"]) ?>
|
||||
</div>
|
||||
|
||||
<?= $this->formTag([], ['id' => "crop", 'level' => 'member'], function(){ ?>
|
||||
<?= $this->hiddenFieldTag("id", $this->image->id) ?>
|
||||
<?= $this->hiddenFieldTag("left", 0) ?>
|
||||
<?= $this->hiddenFieldTag("right", 0) ?>
|
||||
<?= $this->hiddenFieldTag("top", 0) ?>
|
||||
<?= $this->hiddenFieldTag("bottom", 0) ?>
|
||||
<?php }) ?>
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
function onEndCrop(coords, dimensions) {
|
||||
$("left").value = (coords.x1 / $("image").width).toFixed(4);
|
||||
$("right").value = (coords.x2 / $("image").width).toFixed(4);
|
||||
$("top").value = (coords.y1 / $("image").height).toFixed(4);
|
||||
$("bottom").value = (coords.y2 / $("image").height).toFixed(4);
|
||||
}
|
||||
|
||||
// example with a preview of crop results, must have minimumm dimensions
|
||||
var width = $("image").width;
|
||||
var height = $("image").height;
|
||||
var options =
|
||||
{
|
||||
displayOnInit: true,
|
||||
onEndCrop: onEndCrop,
|
||||
minWidth: 1,
|
||||
minHeight: 1
|
||||
}
|
||||
|
||||
'/* Default to a square selection. */'
|
||||
if(width < height)
|
||||
options.onloadCoords = { x1: width/4, y1: width/4, x2: width*2/4, y2: width*2/4 }
|
||||
else
|
||||
options.onloadCoords = { x1: height/4, y1: height/4, x2: height*2/4, y2: height*2/4 }
|
||||
|
||||
new Cropper.ImgWithPreview("image", options)
|
||||
|
||||
OnKey(13, {AlwaysAllowOpera: true}, function(e) {
|
||||
$("crop").submit();
|
||||
return true;
|
||||
});
|
||||
|
||||
</script>
|
||||
</div>
|
191
app/views/inline/edit.php
Executable file
191
app/views/inline/edit.php
Executable file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
if ($this->inline->inline_images->size() > 0) {
|
||||
list($block, $script, $inline_html_id) = $this->format_inline($this->inline, 0, "inline", "");
|
||||
} else {
|
||||
$block = $script = $inline_html_id = null;
|
||||
}
|
||||
?>
|
||||
|
||||
<div>
|
||||
<?= $this->t('.tag', ['id' => $this->inline->id]) ?>
|
||||
<?php if (current_user()->has_permission($this->inline)) : ?>
|
||||
|
||||
| <a href="#" onclick='InlineImage.expand("<?= $inline_html_id ?>"); return false;'><?= $this->t('.preview') ?></a>
|
||||
|
||||
<?php if ($this->inline->inline_images->size() < 9) : ?>
|
||||
<span id="post-add-button">| <a href="#" onclick="show_post_add(); return false;"><?= $this->t('.add_image') ?></a></span>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
<p>
|
||||
|
||||
|
||||
<div id="post-add" style="display: none;">
|
||||
<?= $this->formTag(['action' => "add_image"], ['level' => 'member', 'multipart' => true], function(){ ?>
|
||||
<?= $this->hiddenFieldTag("id", $this->inline->id) ?>
|
||||
<div id="posts">
|
||||
<table class="form">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="15%"><label for="image_file"><?= $this->t('.file') ?></label></th>
|
||||
<td width="85%"><?= $this->fileField("image", "file", ['size' => 50, 'tabindex' => 1]) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
<label for="image_source"><?= $this->t('.source') ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<?= $this->textField('image', 'source', ['size' => 50, 'tabindex' => 2]) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>
|
||||
<?= $this->submitTag($this->t('.add_do')) ?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php }) ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="width: 100%; overflow: auto;">
|
||||
<?= $block ?>
|
||||
</div>
|
||||
|
||||
<div id="inline-edit">
|
||||
<?php foreach ($this->inline->inline_images as $image) : ?>
|
||||
<?= $this->formTag(['action' => "delete_image"], ['id' => "delete-image-" . $image->id], function() use ($image) { ?>
|
||||
<?= $this->hiddenFieldTag("id", $image->id) ?>
|
||||
<?php }) ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?= $this->formTag('#update', function() { ?>
|
||||
<label for="inline_description"><?= $this->t('.description') ?>:</label>
|
||||
<br>
|
||||
<span id="inline-description">
|
||||
<a id="inline-description-edit-button" href="#" onclick="show_edit_desc(); return false;">
|
||||
<?= $this->format_text($this->inline->description) ?>
|
||||
|
||||
<?php if (!$this->inline->description) echo $this->t('.add_set_description_info') ?>
|
||||
</a>
|
||||
<br>
|
||||
</span>
|
||||
|
||||
<div id="inline-description-edit" style="display: none;">
|
||||
<?= $this->textArea('inline', 'description', ['size' => "40x5"]) ?>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<?php foreach ($this->inline->inline_images as $image) : ?>
|
||||
<div id="inline-<?= $image->id ?>" class="inline-image-entry" style="margin-bottom: 1.5em;">
|
||||
<div style="height: 1.6em;">
|
||||
<span style="line-height: 1.6em;">
|
||||
<?php if (current_user()->has_permission($this->inline)) : ?>
|
||||
<?= $this->linkTo($this->t('.remove'), "#", ['onclick' => "if(confirm('" . $this->t('.remove_confirm') . "')) $('delete-image-" . $image->id . "').submit(); return false;"]) ?>
|
||||
| <?= $this->linkToFunction($this->t('.move.up'), "orderShift(" . $image->id . ", -1)") ?>
|
||||
| <?= $this->linkToFunction($this->t('.move.down'), "orderShift(" . $image->id . ", +1)") ?>
|
||||
|
|
||||
<a href="#" id="image-description-<?= $image->id ?>" onclick="show_edit_inline_desc(<?= $image->id ?>); return false;">
|
||||
<?php if (!$image->description) : ?>
|
||||
<?= $this->t('.add_image_description') ?>
|
||||
<?php else: ?>
|
||||
<?= $this->h($image->description) ?>
|
||||
<?php endif ?>
|
||||
</a>
|
||||
|
||||
<span id="image-description-edit-<?= $image->id ?>" style="display: none;">
|
||||
<?= $this->textFieldTag("image[" . $image->id . "][description]", $image->description, ['size' => 40, 'disabled' => (!current_user()->has_permission($this->inline))]) ?>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<?= $this->h($image->description) ?>
|
||||
<?php endif ?>
|
||||
</span>
|
||||
</div>
|
||||
<img style="display: inline" src="<?= $image->preview_url() ?>" width="<?= $image->preview_dimensions()['width'] ?>" height="<?= $image->preview_dimensions()['height'] ?>"></img>
|
||||
|
||||
<?= $this->hiddenFieldTag("image[" . $image->id . "][sequence]", $image->sequence, ['size' => 10, 'disabled' => (!current_user()->has_permission($this->inline)), 'class' => "inline-sequence"]) ?>
|
||||
<div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?= $this->hiddenFieldTag("id", $this->inline->id) ?>
|
||||
<?= $this->submitTag($this->t('.save'), ['disabled' => (!current_user()->has_permission($this->inline))]) ?>
|
||||
<?php }) ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
<?= $script ?>
|
||||
InlineImage.init();
|
||||
|
||||
function show_post_add()
|
||||
{
|
||||
$("post-add").show();
|
||||
$("post-add-button").hide();
|
||||
}
|
||||
|
||||
function show_edit_desc()
|
||||
{
|
||||
$("inline-description-edit").show();
|
||||
$("inline-description").hide();
|
||||
$("inline-description-edit").down("textarea").focus();
|
||||
}
|
||||
|
||||
function show_edit_inline_desc(id)
|
||||
{
|
||||
$("image-description-" + id).hide();
|
||||
$("image-description-edit-" + id).show();
|
||||
$("image-description-edit-" + id).down("input").focus();
|
||||
}
|
||||
|
||||
function orderShift(id, direction) {
|
||||
var first_image = $("inline-" + id);
|
||||
var second_image;
|
||||
if(direction > 0)
|
||||
{
|
||||
var sibs = first_image.nextSiblings();
|
||||
second_image = sibs[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
second_image = first_image;
|
||||
var sibs = first_image.previousSiblings();
|
||||
first_image = sibs[0];
|
||||
}
|
||||
if(!first_image || !second_image)
|
||||
return;
|
||||
|
||||
{
|
||||
var swap = first_image.down(".inline-sequence").value;
|
||||
first_image.down(".inline-sequence").value = second_image.down(".inline-sequence").value;
|
||||
second_image.down(".inline-sequence").value = swap;
|
||||
}
|
||||
var parentNode = second_image.parentNode;
|
||||
parentNode.removeChild(second_image);
|
||||
parentNode.insertBefore(second_image, first_image);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<?= $this->formTag(['action' => "delete"], ['id' => "delete-group"], function(){ ?>
|
||||
<?= $this->hiddenFieldTag("id", $this->inline->id) ?>
|
||||
<?php }) ?>
|
||||
<?= $this->formTag(['action' => "copy"], ['id' => "copy-group"], function() { ?>
|
||||
<?= $this->hiddenFieldTag("id", $this->inline->id) ?>
|
||||
<?php }) ?>
|
||||
|
||||
<?php $this->contentFor('subnavbar', function() { ?>
|
||||
<?php if (current_user()->has_permission($this->inline)) : ?>
|
||||
<li><?= $this->linkTo($this->t('.delete'), "#", ['onclick' => "if(confirm('" . $this->t('.delete_confirm') . "')) $('delete-group').submit(); return false;"]) ?></li>
|
||||
<li><?= $this->linkTo($this->t('.crop'), ['action' => "crop", 'id' => $this->inline->id]) ?></li>
|
||||
<?php endif ?>
|
||||
|
||||
<li><?= $this->linkTo($this->t('.copy'), "#", ['onclick' => "$('copy-group').submit(); return false;", 'level' => 'member']) ?></li>
|
||||
<?php }) ?>
|
||||
|
||||
<?= $this->partial("footer") ?>
|
45
app/views/inline/index.php
Executable file
45
app/views/inline/index.php
Executable file
@ -0,0 +1,45 @@
|
||||
<div id="pool-index">
|
||||
<table width="100%" class="highlightable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="40px"><?= $this->t('.first_image') ?></th>
|
||||
<th width="60%"><?= $this->t('.description2') ?></th>
|
||||
<th width="*"><?= $this->t('.user') ?></th>
|
||||
<th width="*"><?= $this->t('.images') ?></th>
|
||||
<th width="*"><?= $this->t('.created') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->inlines as $p) : ?>
|
||||
<tr class="<?= $this->cycle('even', 'odd') ?>" id="p<?= $p->id ?>">
|
||||
<td>
|
||||
<a href='<?= $this->urlFor(['#edit', 'id' => $p->id]) ?>'>
|
||||
<?php if ($p->inline_images->any()) : ?>
|
||||
<?= $this->imageTag($p->inline_images[0]->preview_url(), ['alt' => "thumb", 'width' => $p->inline_images[0]->preview_dimensions()['width'], 'height' => $p->inline_images[0]->preview_dimensions()['height']]) ?>
|
||||
<?php else: ?>
|
||||
(no images)
|
||||
<?php endif ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><?= $this->h($p->description) ?></td>
|
||||
<td><?= $this->linkTo($this->h($p->user->pretty_name()), ["user#show", 'id' => $p->user->id]) ?></td>
|
||||
<td><?= $p->inline_images->size() ?></td>
|
||||
<td><?= $this->t('time.x_ago', ['t' => $this->t($this->timeAgoInWords($p->created_at))]) ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="paginator">
|
||||
<?= $this->willPaginate($this->inlines) ?>
|
||||
</div>
|
||||
|
||||
<?= $this->formTag(["#create"], ['id' => "create-new"], function(){ ?>
|
||||
<?php }) ?>
|
||||
|
||||
<?php $this->contentFor('subnavbar', function() { ?>
|
||||
<li><?= $this->linkTo($this->t('.create'), "#", ['level' => 'member', 'onclick' => "$('create-new').submit(); return false;"]) ?></li>
|
||||
<?php }) ?>
|
||||
|
||||
<?= $this->partial("footer") ?>
|
@ -18,4 +18,10 @@ en:
|
||||
notes_create_notice: To create a note, <br/>Shift + Click + Drag<br/> over the image. More info in the %{notes_help}. (%{close})
|
||||
|
||||
static13a: Moderate
|
||||
static62a: Index
|
||||
static62a: Index
|
||||
|
||||
# These ones are missing:
|
||||
inline:
|
||||
index:
|
||||
description2: Image-set description
|
||||
created: Created
|
74
db/table_schema/production/inline_images.php
Normal file
74
db/table_schema/production/inline_images.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
return array (
|
||||
0 =>
|
||||
array (
|
||||
'id' =>
|
||||
array (
|
||||
'type' => 'int(11)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'inline_id' =>
|
||||
array (
|
||||
'type' => 'int(11)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'md5' =>
|
||||
array (
|
||||
'type' => 'varchar(32)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'file_ext' =>
|
||||
array (
|
||||
'type' => 'varchar(4)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'description' =>
|
||||
array (
|
||||
'type' => 'text',
|
||||
'default' => NULL,
|
||||
),
|
||||
'sequence' =>
|
||||
array (
|
||||
'type' => 'int(11)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'width' =>
|
||||
array (
|
||||
'type' => 'int(11)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'height' =>
|
||||
array (
|
||||
'type' => 'int(11)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'sample_width' =>
|
||||
array (
|
||||
'type' => 'int(11)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'sample_height' =>
|
||||
array (
|
||||
'type' => 'int(11)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'created_at' =>
|
||||
array (
|
||||
'type' => 'datetime',
|
||||
'default' => NULL,
|
||||
),
|
||||
'updated_at' =>
|
||||
array (
|
||||
'type' => 'datetime',
|
||||
'default' => NULL,
|
||||
),
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'pri' =>
|
||||
array (
|
||||
0 => 'id',
|
||||
),
|
||||
),
|
||||
)
|
||||
;
|
39
db/table_schema/production/inlines.php
Normal file
39
db/table_schema/production/inlines.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
return array (
|
||||
0 =>
|
||||
array (
|
||||
'id' =>
|
||||
array (
|
||||
'type' => 'int(11)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'user_id' =>
|
||||
array (
|
||||
'type' => 'int(11)',
|
||||
'default' => NULL,
|
||||
),
|
||||
'description' =>
|
||||
array (
|
||||
'type' => 'text',
|
||||
'default' => NULL,
|
||||
),
|
||||
'created_at' =>
|
||||
array (
|
||||
'type' => 'datetime',
|
||||
'default' => NULL,
|
||||
),
|
||||
'updated_at' =>
|
||||
array (
|
||||
'type' => 'datetime',
|
||||
'default' => NULL,
|
||||
),
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'pri' =>
|
||||
array (
|
||||
0 => 'id',
|
||||
),
|
||||
),
|
||||
)
|
||||
;
|
15
lib/Moebooru/TempfilePrefix.php
Executable file
15
lib/Moebooru/TempfilePrefix.php
Executable file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace Moebooru;
|
||||
|
||||
trait TempfilePrefix
|
||||
{
|
||||
public $tempfile_prefix;
|
||||
|
||||
public function tempfile_prefix()
|
||||
{
|
||||
if (!$this->tempfile_prefix) {
|
||||
$this->tempfile_prefix = \Rails::publicPath() . '/data/temp-' . uniqid('tfp_');
|
||||
}
|
||||
return $this->tempfile_prefix;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user