Aaron van Geffen
e28fcd8b03
Removes the intermediate confirmation page, instead using JavaScript for confirmation. Fixes an XSS issue, in that the previous method was not passing or checking the session (!)
310 lines
9.2 KiB
PHP
310 lines
9.2 KiB
PHP
<?php
|
|
/*****************************************************************************
|
|
* EditAssetForm.php
|
|
* Contains the edit asset template.
|
|
*
|
|
* Kabuki CMS (C) 2013-2015, Aaron van Geffen
|
|
*****************************************************************************/
|
|
|
|
class EditAssetForm extends Template
|
|
{
|
|
private $asset;
|
|
private $thumbs;
|
|
|
|
public function __construct(Asset $asset, array $thumbs = [])
|
|
{
|
|
$this->asset = $asset;
|
|
$this->thumbs = $thumbs;
|
|
}
|
|
|
|
public function html_main()
|
|
{
|
|
echo '
|
|
<form id="asset_form" action="" method="post" enctype="multipart/form-data">
|
|
<div class="content-box">
|
|
<div class="float-end">
|
|
<a class="btn btn-danger" href="', $this->asset->getDeleteUrl(), '&',
|
|
Session::getSessionTokenKey(), '=', Session::getSessionToken(),
|
|
'" onclick="return confirm(\'Are you sure you want to delete this asset?\');">',
|
|
'Delete asset</a>
|
|
<button class="btn btn-primary" type="submit">Save asset data</button>
|
|
</div>
|
|
<h2>Edit asset \'', $this->asset->getTitle(), '\' (', $this->asset->getFilename(), ')</h2>
|
|
</div>';
|
|
|
|
$this->section_replace();
|
|
|
|
echo '
|
|
<div class="row">
|
|
<div class="col-md-8">';
|
|
|
|
$this->section_key_info();
|
|
$this->section_asset_meta();
|
|
|
|
echo '
|
|
</div>
|
|
<div class="col-md-4">';
|
|
|
|
if (!empty($this->thumbs))
|
|
$this->section_thumbnails();
|
|
|
|
$this->section_linked_tags();
|
|
|
|
echo '
|
|
</div>';
|
|
|
|
$this->section_crop_editor();
|
|
|
|
echo '
|
|
</div>
|
|
</form>';
|
|
}
|
|
|
|
protected function section_key_info()
|
|
{
|
|
$date_captured = $this->asset->getDateCaptured();
|
|
echo '
|
|
<div class="content-box key_info">
|
|
<h3>Key info</h3>
|
|
|
|
<div class="row mb-2">
|
|
<label class="col-form-label col-sm-3">Title (internal):</label>
|
|
<div class="col-sm">
|
|
<input class="form-control" type="text" name="title" maxlength="255" size="70" value="', $this->asset->getTitle(), '">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<label class="col-form-label col-sm-3">URL slug:</label>
|
|
<div class="col-sm">
|
|
<input class="form-control" type="text" name="slug" maxlength="255" size="70" value="', $this->asset->getSlug(), '">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<label class="col-form-label col-sm-3">Date captured:</label>
|
|
<div class="col-sm">
|
|
<input class="form-control" name="date_captured" size="30" value="',
|
|
$date_captured ? $date_captured->format('Y-m-d H:i:s') : '', '" placeholder="Y-m-d H:i:s">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<label class="col-form-label col-sm-3">Display priority:</label>
|
|
<div class="col-sm-3">
|
|
<input class="form-control" type="number" name="priority" min="0" max="100" step="1" value="', $this->asset->getPriority(), '">
|
|
</div>
|
|
</div>
|
|
</div>';
|
|
}
|
|
|
|
protected function section_linked_tags()
|
|
{
|
|
echo '
|
|
<div class="content-box linked_tags">
|
|
<h3>Linked tags</h3>
|
|
<ul class="list-unstyled" id="tag_list">';
|
|
|
|
foreach ($this->asset->getTags() as $tag)
|
|
echo '
|
|
<li>
|
|
<input class="tag_check" type="checkbox" name="tag[', $tag->id_tag, ']" id="linked_tag_', $tag->id_tag, '" title="Uncheck to delete" checked>
|
|
', $tag->tag, '
|
|
</li>';
|
|
|
|
echo '
|
|
<li id="new_tag_container"><input class="form-control" type="text" id="new_tag" placeholder="Type to link a new tag"></li>
|
|
</ul>
|
|
</div>
|
|
<script type="text/javascript" src="', BASEURL, '/js/ajax.js"></script>
|
|
<script type="text/javascript" src="', BASEURL, '/js/autosuggest.js"></script>
|
|
<script type="text/javascript">
|
|
setTimeout(function() {
|
|
var tag_autosuggest = new TagAutoSuggest({
|
|
inputElement: "new_tag",
|
|
listElement: "tag_list",
|
|
baseUrl: "', BASEURL, '",
|
|
appendCallback: function(item) {
|
|
if (document.getElementById("linked_tag_" + item.id_tag)) {
|
|
return;
|
|
}
|
|
|
|
var newCheck = document.createElement("input");
|
|
newCheck.type = "checkbox";
|
|
newCheck.name = "tag[" + item.id_tag + "]";
|
|
newCheck.id = "linked_tag_" + item.id_tag;
|
|
newCheck.title = "Uncheck to delete";
|
|
newCheck.checked = "checked";
|
|
|
|
var newNode = document.createElement("li");
|
|
newNode.appendChild(newCheck);
|
|
|
|
var newLabel = document.createTextNode(item.label);
|
|
newNode.appendChild(newLabel);
|
|
|
|
var list = document.getElementById("tag_list");
|
|
var input = document.getElementById("new_tag_container");
|
|
list.insertBefore(newNode, input);
|
|
}
|
|
});
|
|
}, 100);
|
|
</script>';
|
|
}
|
|
|
|
protected function section_thumbnails()
|
|
{
|
|
echo '
|
|
<div class="content-box linked_thumbs">
|
|
<h3>Thumbnails</h3>
|
|
View: <select class="form-select w-auto d-inline" id="thumbnail_src">';
|
|
|
|
$first = INF;
|
|
foreach ($this->thumbs as $i => $thumb)
|
|
{
|
|
$first = min($i, $first);
|
|
|
|
echo '
|
|
<option data-url="', $thumb['url'], '" data-crop_width="', $thumb['dimensions'][0], '" data-crop_height="', $thumb['dimensions'][1], '"',
|
|
isset($thumb['crop_method']) ? ' data-crop_method="' . $thumb['crop_method'] . '"' : '',
|
|
isset($thumb['crop_region']) ? ' data-crop_region="' . $thumb['crop_region'] . '"' : '', '>
|
|
', implode('x', $thumb['dimensions']);
|
|
|
|
if ($thumb['cropped'])
|
|
{
|
|
echo ' (';
|
|
switch ($thumb['crop_method'])
|
|
{
|
|
case 'b': echo 'bottom'; break;
|
|
case 'e': echo 'exact'; break;
|
|
case 's': echo 'slice'; break;
|
|
case 't': echo 'top'; break;
|
|
default: echo 'centre'; break;
|
|
}
|
|
echo ' crop)';
|
|
}
|
|
elseif ($thumb['custom_image'])
|
|
echo ' (custom)';
|
|
|
|
echo '
|
|
</option>';
|
|
}
|
|
|
|
echo '
|
|
</select>
|
|
<a id="thumbnail_link" href="', $this->thumbs[$first]['url'], '" target="_blank">
|
|
<img id="thumbnail" src="', $this->thumbs[$first]['url'], '" alt="Thumbnail" style="width: 100%; height: auto;">
|
|
</a>
|
|
</div>
|
|
<script type="text/javascript" defer="defer">
|
|
document.getElementById("thumbnail_src").addEventListener("change", event => {
|
|
let selection = event.target.options[event.target.selectedIndex];
|
|
document.getElementById("thumbnail_link").href = selection.dataset.url;
|
|
document.getElementById("thumbnail").src = selection.dataset.url;
|
|
});
|
|
</script>';
|
|
}
|
|
|
|
protected function section_crop_editor()
|
|
{
|
|
if (!$this->asset->isImage())
|
|
return;
|
|
|
|
echo '
|
|
<script type="text/javascript" src="', BASEURL, '/js/crop_editor.js"></script>
|
|
<script type="text/javascript" defer="defer">
|
|
let editor = new CropEditor({
|
|
submit_url: "', BASEURL, '/editasset/",
|
|
original_image_src: "', $this->asset->getUrl(), '",
|
|
editor_container_parent_id: "asset_form",
|
|
thumbnail_select_id: "thumbnail_src",
|
|
drag_target: ".crop_image_container",
|
|
asset_id: ', $this->asset->getId(), ',
|
|
after_save: function(data) {
|
|
// Update thumbnail
|
|
document.getElementById("thumbnail").src = data.url + "?" + (new Date()).getTime();
|
|
|
|
// Update select
|
|
let src = document.getElementById("thumbnail_src");
|
|
let option = src.options[src.selectedIndex];
|
|
option.dataset.crop_region = data.value;
|
|
option.textContent = option.textContent.replace(/top|bottom|centre|slice/, "exact");
|
|
|
|
// TODO: update meta
|
|
}
|
|
});
|
|
</script>';
|
|
}
|
|
|
|
protected function section_asset_meta()
|
|
{
|
|
echo '
|
|
<div class="content-box asset_meta mt-2">
|
|
<h3>Asset meta data</h3>';
|
|
|
|
$i = 0;
|
|
foreach ($this->asset->getMeta() as $key => $meta)
|
|
{
|
|
echo '
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" name="meta_key[', $i, ']" value="', htmlspecialchars($key), '" placeholder="key">
|
|
<input type="text" class="form-control" name="meta_value[', $i, ']" value="', htmlspecialchars($meta), '" placeholder="value">
|
|
</div>';
|
|
$i++;
|
|
}
|
|
|
|
|
|
echo '
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" name="meta_key[', $i + 1, ']" value="" placeholder="key">
|
|
<input type="text" class="form-control" name="meta_value[', $i + 1, ']" value="" placeholder="value">
|
|
</div>
|
|
<div class="text-end mt-3">
|
|
<button class="btn btn-primary" type="submit">Save metadata</button>
|
|
</div>
|
|
</div>';
|
|
}
|
|
|
|
protected function section_replace()
|
|
{
|
|
echo '
|
|
<div class="content-box replace_asset mt-2">
|
|
<h3>Replace asset</h3>
|
|
File: <input class="form-control d-inline w-auto" type="file" name="replacement">
|
|
Target: <select class="form-select d-inline w-auto" name="replacement_target">
|
|
<option value="full">master file</option>';
|
|
|
|
foreach ($this->thumbs as $thumb)
|
|
{
|
|
echo '
|
|
<option value="thumb_', implode('x', $thumb['dimensions']);
|
|
|
|
if ($thumb['cropped'])
|
|
echo $thumb['crop_method'] === 'c' ? '_c' : '_c' . $thumb['crop_method'];
|
|
|
|
echo '">
|
|
thumbnail (', implode('x', $thumb['dimensions']);
|
|
|
|
if ($thumb['cropped'])
|
|
{
|
|
echo ', ';
|
|
switch ($thumb['crop_method'])
|
|
{
|
|
case 'b': echo 'bottom'; break;
|
|
case 'e': echo 'exact'; break;
|
|
case 's': echo 'slice'; break;
|
|
case 't': echo 'top'; break;
|
|
default: echo 'centre'; break;
|
|
}
|
|
echo ' crop';
|
|
}
|
|
elseif ($thumb['custom_image'])
|
|
echo ', custom';
|
|
|
|
echo ')
|
|
</option>';
|
|
}
|
|
|
|
echo '
|
|
</select>
|
|
<button class="btn btn-primary" type="submit">Save asset</button>
|
|
</div>';
|
|
}
|
|
}
|