enabled uploading images from clipboard on ticket edit.
This commit is contained in:
parent
2a3465fff8
commit
8c8de5ec34
@ -145,4 +145,41 @@ class AttachmentController {
|
|||||||
// remove DB row
|
// remove DB row
|
||||||
$db->exec('DELETE FROM attachments WHERE id =?', [$attachment_id]);
|
$db->exec('DELETE FROM attachments WHERE id =?', [$attachment_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// view attachment
|
||||||
|
public function view($f3){
|
||||||
|
$this->check_access($f3);
|
||||||
|
|
||||||
|
$attachment_id = (int) $f3->get('PARAMS.id');
|
||||||
|
$db = $f3->get('DB');
|
||||||
|
|
||||||
|
$rows = $db->exec('SELECt * FROM attachments WHERE id = ?', [$attachment_id]);
|
||||||
|
|
||||||
|
if(!$rows){
|
||||||
|
$f3->error(404, "File not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment = $rows[0];
|
||||||
|
$file_path = $attachment['path'];
|
||||||
|
$file_name = $attachment['file_name'];
|
||||||
|
|
||||||
|
if(!file_exists($file_path)){
|
||||||
|
$f3->error(404, "File not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect mime type
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||||
|
$mime_type = finfo_file($finfo, $file_path);
|
||||||
|
finfo_close($finfo);
|
||||||
|
|
||||||
|
header('Content-Type: ' . $mime_type);
|
||||||
|
header('Content-Disposition: inline; filename="' . basename($file_name) . '"');
|
||||||
|
header('Content-Length: ' . filesize($file_path));
|
||||||
|
|
||||||
|
flush();
|
||||||
|
readfile($file_path);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
89
ui/parts/clipboard.html
Normal file
89
ui/parts/clipboard.html
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<div class="block">
|
||||||
|
<style>
|
||||||
|
#upload-area {
|
||||||
|
height: 250px;
|
||||||
|
border: 2px dashed #aaa;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #555;
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#upload-area.hover {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
#preview {
|
||||||
|
max-width:100%;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="upload-area" contenteditable="true">
|
||||||
|
Paste or drag an image here
|
||||||
|
</div>
|
||||||
|
<img id="preview" alt="image preview" hidden>
|
||||||
|
<p id="status"></p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const area = document.getElementById('upload-area');
|
||||||
|
const preview = document.getElementById('preview');
|
||||||
|
const status = document.getElementById('status');
|
||||||
|
|
||||||
|
async function uploadImage(file){
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
preview.src = reader.result;
|
||||||
|
preview.hidden = false;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('attachment', file);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/ticket/{{@ticket->id}}/attachments/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
const text = await res.text();
|
||||||
|
status.textContent = text;
|
||||||
|
} catch (e) {
|
||||||
|
status.textContent = 'upload failed.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// paste
|
||||||
|
area.addEventListener('paste', (e) => {
|
||||||
|
for(let item of e.clipboardData.items){
|
||||||
|
if(item.type.startsWith('image/')){
|
||||||
|
uploadImage(item.getAsFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// drag and drop
|
||||||
|
area.addEventListener('dragover', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
area.classList.add('hover');
|
||||||
|
});
|
||||||
|
|
||||||
|
area.addEventListener('dragLeave', ()=> {
|
||||||
|
area.classList.remove('hover');
|
||||||
|
});
|
||||||
|
|
||||||
|
area.addEventListener('drop', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
area.classList.remove('hover');
|
||||||
|
const files = e.dataTransfer.files;
|
||||||
|
for(let file of files){
|
||||||
|
if(file.type.startsWith('image/')){
|
||||||
|
uploadImage(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
@ -28,6 +28,12 @@
|
|||||||
</repeat>
|
</repeat>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<hr>
|
||||||
|
<div>
|
||||||
|
<repeat group="{{ @attachments }}" value="{{ @attach }}">
|
||||||
|
<img src="/attachment/{{@attach.id}}/view">
|
||||||
|
</repeat>
|
||||||
|
</div>
|
||||||
</check>
|
</check>
|
||||||
</check>
|
</check>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
|
|||||||
@ -4,9 +4,10 @@
|
|||||||
<form action="/ticket/create" method="POST">
|
<form action="/ticket/create" method="POST">
|
||||||
|
|
||||||
<bulma type="H_FIELD_INPUT" label="Title:" name="title" value=""></bulma>
|
<bulma type="H_FIELD_INPUT" label="Title:" name="title" value=""></bulma>
|
||||||
|
<bulma type="H_FIELD_INPUT" label="Created At:" name="created_at" value=""></bulma>
|
||||||
<bulma type="H_FIELD_TEXTAREA" label="Description:" name="description" value=""></bulma>
|
<bulma type="H_FIELD_TEXTAREA" label="Description:" name="description" value=""></bulma>
|
||||||
|
|
||||||
|
<!-- TODO implement priority and status -->
|
||||||
<bulma type="H_FIELD_SELECT" label="Priority:" name="priority" options="['Low', 'Medium', 'High']" selected="Medium"></bulma>
|
<bulma type="H_FIELD_SELECT" label="Priority:" name="priority" options="['Low', 'Medium', 'High']" selected="Medium"></bulma>
|
||||||
<bulma type="H_FIELD_SELECT" label="Status:" name="status" options="['New', 'In Progress', 'On Hold', 'Completed']" selected="New"></bulma>
|
<bulma type="H_FIELD_SELECT" label="Status:" name="status" options="['New', 'In Progress', 'On Hold', 'Completed']" selected="New"></bulma>
|
||||||
|
|
||||||
|
|||||||
@ -3,12 +3,14 @@
|
|||||||
<form action="/ticket/{{ @PARAMS.id }}/update" method="POST">
|
<form action="/ticket/{{ @PARAMS.id }}/update" method="POST">
|
||||||
|
|
||||||
<bulma type="H_FIELD_INPUT" label="Title:" name="title" value="{{@ticket.title}}"></bulma>
|
<bulma type="H_FIELD_INPUT" label="Title:" name="title" value="{{@ticket.title}}"></bulma>
|
||||||
|
<bulma type="H_FIELD_INPUT" label="Created At:" name="created_at" value="{{@ticket.created_at}}"></bulma>
|
||||||
<bulma type="H_FIELD_TEXTAREA" label="Description:" name="description" value="{{@ticket.description}}"></bulma>
|
<bulma type="H_FIELD_TEXTAREA" label="Description:" name="description" value="{{@ticket.description}}"></bulma>
|
||||||
|
|
||||||
|
|
||||||
<bulma type="H_FIELD_SELECT" label="Priority:" name="priority" options="['Low', 'Medium', 'High']" selected="{{@ticket.priority}}"></bulma>
|
<bulma type="H_FIELD_SELECT" label="Priority:" name="priority" options="['Low', 'Medium', 'High']" selected="{{@ticket.priority}}"></bulma>
|
||||||
<bulma type="H_FIELD_SELECT" label="Status:" name="status" options="['New', 'In Progress', 'On Hold', 'Completed']" selected="{{@ticket.status}}"></bulma>
|
<bulma type="H_FIELD_SELECT" label="Status:" name="status" options="['New', 'In Progress', 'On Hold', 'Completed']" selected="{{@ticket.status}}"></bulma>
|
||||||
|
|
||||||
|
<include href="/ui/parts/clipboard.html"></include>
|
||||||
|
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<h3 class="title is-5">Custom Fields</h3>
|
<h3 class="title is-5">Custom Fields</h3>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user