[notes] replace all the javascript
This commit is contained in:
parent
48b3de3c6e
commit
05a981d935
11 changed files with 393 additions and 321 deletions
Binary file not shown.
Before Width: | Height: | Size: 72 B |
Binary file not shown.
Before Width: | Height: | Size: 72 B |
File diff suppressed because one or more lines are too long
2
ext/notes/lib/jquery.imgnotes-1.0.min.css
vendored
2
ext/notes/lib/jquery.imgnotes-1.0.min.css
vendored
|
@ -1,2 +0,0 @@
|
|||
/** imgnotes jQuery plugin v1.0.0 **/
|
||||
p{font-family:"Times New Roman";font-size:14px}.ui-widget-content{font-family:"Times New Roman"}.ui-widget-content a{color:blue}.marker{position:absolute;width:27px;height:40px}.marker-text{position:absolute;top:10%;width:100%;margin:0 0 0 0;z-index:1;font-size:12px;font-weight:700;text-align:center;color:#fff}.pin{position:absolute;width:20px;height:30px}.pin-text{position:absolute;top:10%;width:100%;margin:0 0 0 0;font-size:14px;font-weight:700;text-align:center;color:#000}.tooltip{position:relative;display:inline-block}.tooltip .tooltiptext{visibility:visible;width:180px;background-color:#fff;color:#000;text-align:center;padding:5px 0;border-radius:6px;position:absolute;z-index:1;bottom:7px;left:50%;margin-left:-90px}.tooltip .tooltiptext::after{content:"";position:absolute;top:100%;left:50%;margin-left:-7px;border-width:7px;border-style:solid;border-color:#fff transparent transparent transparent}table.gridtable{font-family:verdana,arial,sans-serif;font-size:11px;color:#333;border-width:1px;border-color:#666;border-collapse:collapse}table.gridtable th{border-width:1px;padding:8px;border-style:solid;border-color:#666;background-color:#dedede}table.gridtable td{border-width:1px;padding:8px;border-style:solid;border-color:#666;background-color:#fff}
|
15
ext/notes/lib/jquery.imgnotes-1.0.min.js
vendored
15
ext/notes/lib/jquery.imgnotes-1.0.min.js
vendored
|
@ -1,15 +0,0 @@
|
|||
/**
|
||||
* imgnotes jQuery plugin
|
||||
* version 1.0
|
||||
*
|
||||
* Copyright (c) 2008 - Dr. Tarique Sani <tarique@sanisoft.com>
|
||||
*
|
||||
* Dual licensed under the MIT (MIT-LICENSE.txt)
|
||||
* and GPL (GPL-LICENSE.txt) licenses.
|
||||
*
|
||||
* @URL http://www.sanisoft.com/blog/2008/05/26/img-notes-jquery-plugin/
|
||||
* @Example example.html
|
||||
*
|
||||
**/
|
||||
|
||||
(function(e){function t(){e(".note").hover(function(){e(".note").show();e(this).next(".notep").show();e(this).next(".notep").css("z-index",1e4)},function(){e(".note").show();e(this).next(".notep").hide();e(this).next(".notep").css("z-index",0)})}function n(t){note_left=parseInt(imgOffset.left)+parseInt(t.x1);note_top=parseInt(imgOffset.top)+parseInt(t.y1);note_p_top=note_top+parseInt(t.height)+5;note_area_div=e("<div class='note'></div>").css({left:note_left+"px",top:note_top+"px",width:t.width+"px",height:t.height+"px"});note_text_div=e('<div class="notep" >'+t.note+"</div>").css({left:note_left+"px",top:note_p_top+"px"});e("body").append(note_area_div);e("body").append(note_text_div)}function r(t){if(true!==t){return}notes_icon_left=parseInt(imgOffset.left)+parseInt(imgWidth)-36;notes_icon_top=parseInt(imgOffset.top)+parseInt(imgHieght)-40;notes_icon_div=note_area_div=e("<div class='notesicon'></div>").css({left:notes_icon_left+"px",top:notes_icon_top+"px"});e("body").append(notes_icon_div);e(".notesicon").toggle(function(){e.fn.imgNotes.showAll()},function(){e.fn.imgNotes.hideAll()})}e.fn.imgNotes=function(i){if(undefined==s){var s}if(undefined!=i.notes){s=i.notes}if(i.url){e.ajaxSetup({async:false});e.getJSON(i.url,function(e){s=e})}image=this;imgOffset=e(image).offset();imgHieght=e(image).height();imgWidth=e(image).width();e(s).each(function(){n(this)});e(image).hover(function(){e(".note").show()},function(){e(".note").hide();e(".notep").hide()});t();r(i.isMobile);e(window).resize(function(){e(".note").remove();e(".notep").remove();e(".notesicon").remove();imgOffset=e(image).offset();imgHieght=e(image).height();imgWidth=e(image).width();e(s).each(function(){n(this)});t();r(i.isMobile)})};e.fn.imgNotes.showAll=function(){e(".note").show();e(".notep").show()};e.fn.imgNotes.hideAll=function(){e(".note").hide();e(".notep").hide()}})(jQuery);
|
Binary file not shown.
Before Width: | Height: | Size: 43 B |
|
@ -98,26 +98,49 @@ class Notes extends Extension
|
|||
if (!$user->is_anonymous()) {
|
||||
$this->revert_history($noteID, $reviewID);
|
||||
}
|
||||
|
||||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("note/updated"));
|
||||
break;
|
||||
case "add_note":
|
||||
if (!$user->is_anonymous()) {
|
||||
$this->add_new_note();
|
||||
}
|
||||
|
||||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("post/view/".$_POST["image_id"]));
|
||||
break;
|
||||
case "add_request":
|
||||
if (!$user->is_anonymous()) {
|
||||
$this->add_note_request();
|
||||
}
|
||||
|
||||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("post/view/".$_POST["image_id"]));
|
||||
break;
|
||||
case "nuke_requests":
|
||||
if ($user->can(Permissions::NOTES_ADMIN)) {
|
||||
$this->nuke_requests();
|
||||
}
|
||||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("post/view/".$_POST["image_id"]));
|
||||
break;
|
||||
|
||||
case "create_note":
|
||||
$page->set_mode(PageMode::DATA);
|
||||
if (!$user->is_anonymous()) {
|
||||
$note_id = $this->add_new_note();
|
||||
$page->set_data(json_encode([
|
||||
'status' => 'success',
|
||||
'note_id' => $note_id,
|
||||
]));
|
||||
}
|
||||
break;
|
||||
case "update_note":
|
||||
$page->set_mode(PageMode::DATA);
|
||||
if (!$user->is_anonymous()) {
|
||||
$this->update_note();
|
||||
$page->set_data(json_encode(['status' => 'success']));
|
||||
}
|
||||
break;
|
||||
case "delete_note":
|
||||
$page->set_mode(PageMode::DATA);
|
||||
if ($user->can(Permissions::NOTES_ADMIN)) {
|
||||
$this->delete_note();
|
||||
$page->set_data(json_encode(['status' => 'success']));
|
||||
}
|
||||
break;
|
||||
case "nuke_notes":
|
||||
if ($user->can(Permissions::NOTES_ADMIN)) {
|
||||
$this->nuke_notes();
|
||||
|
@ -126,28 +149,7 @@ class Notes extends Extension
|
|||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("post/view/".$_POST["image_id"]));
|
||||
break;
|
||||
case "nuke_requests":
|
||||
if ($user->can(Permissions::NOTES_ADMIN)) {
|
||||
$this->nuke_requests();
|
||||
}
|
||||
|
||||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("post/view/".$_POST["image_id"]));
|
||||
break;
|
||||
case "edit_note":
|
||||
if (!$user->is_anonymous()) {
|
||||
$this->update_note();
|
||||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("post/view/" . $_POST["image_id"]));
|
||||
}
|
||||
break;
|
||||
case "delete_note":
|
||||
if ($user->can(Permissions::NOTES_ADMIN)) {
|
||||
$this->delete_note();
|
||||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("post/view/".$_POST["image_id"]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("note/list"));
|
||||
|
@ -243,32 +245,43 @@ class Notes extends Extension
|
|||
/*
|
||||
* HERE WE ADD A NOTE TO DATABASE
|
||||
*/
|
||||
private function add_new_note()
|
||||
private function add_new_note(): int
|
||||
{
|
||||
global $database, $user;
|
||||
|
||||
$imageID = int_escape($_POST["image_id"]);
|
||||
$user_id = $user->id;
|
||||
$noteX1 = int_escape($_POST["note_x1"]);
|
||||
$noteY1 = int_escape($_POST["note_y1"]);
|
||||
$noteHeight = int_escape($_POST["note_height"]);
|
||||
$noteWidth = int_escape($_POST["note_width"]);
|
||||
$noteText = html_escape($_POST["note_text"]);
|
||||
$note = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
$database->execute(
|
||||
"
|
||||
INSERT INTO notes (enable, image_id, user_id, user_ip, date, x1, y1, height, width, note)
|
||||
VALUES (:enable, :image_id, :user_id, :user_ip, now(), :x1, :y1, :height, :width, :note)",
|
||||
['enable' => 1, 'image_id' => $imageID, 'user_id' => $user_id, 'user_ip' => get_real_ip(), 'x1' => $noteX1, 'y1' => $noteY1, 'height' => $noteHeight, 'width' => $noteWidth, 'note' => $noteText]
|
||||
[
|
||||
'enable' => 1,
|
||||
'image_id' => $note['image_id'],
|
||||
'user_id' => $user->id,
|
||||
'user_ip' => get_real_ip(),
|
||||
'x1' => $note['x1'],
|
||||
'y1' => $note['y1'],
|
||||
'height' => $note['height'],
|
||||
'width' => $note['width'],
|
||||
'note' => $note['note'],
|
||||
]
|
||||
);
|
||||
|
||||
$noteID = $database->get_last_insert_id('notes_id_seq');
|
||||
|
||||
log_info("notes", "Note added {$noteID} by {$user->name}");
|
||||
|
||||
$database->execute("UPDATE images SET notes=(SELECT COUNT(*) FROM notes WHERE image_id=:id1) WHERE id=:id2", ['id1' => $imageID, 'id2' => $imageID]);
|
||||
$database->execute("UPDATE images SET notes=(SELECT COUNT(*) FROM notes WHERE image_id=:id) WHERE id=:id", ['id' => $note['image_id']]);
|
||||
|
||||
$this->add_history(1, $noteID, $imageID, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText);
|
||||
$this->add_history(
|
||||
1, $noteID, $note['image_id'],
|
||||
$note['x1'], $note['y1'],
|
||||
$note['height'], $note['width'],
|
||||
$note['note']
|
||||
);
|
||||
|
||||
return $noteID;
|
||||
}
|
||||
|
||||
private function add_note_request()
|
||||
|
@ -294,15 +307,7 @@ class Notes extends Extension
|
|||
{
|
||||
global $database;
|
||||
|
||||
$note = [
|
||||
"x1" => int_escape($_POST["note_x1"]),
|
||||
"y1" => int_escape($_POST["note_y1"]),
|
||||
"height" => int_escape($_POST["note_height"]),
|
||||
"width" => int_escape($_POST["note_width"]),
|
||||
"note" => $_POST["note_text"],
|
||||
"image_id" => int_escape($_POST["image_id"]),
|
||||
"id" => int_escape($_POST["note_id"])
|
||||
];
|
||||
$note = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
// validate parameters
|
||||
if (empty($note['note'])) {
|
||||
|
@ -312,29 +317,22 @@ class Notes extends Extension
|
|||
$database->execute("
|
||||
UPDATE notes
|
||||
SET x1 = :x1, y1 = :y1, height = :height, width = :width, note = :note
|
||||
WHERE image_id = :image_id AND id = :id", $note);
|
||||
WHERE image_id = :image_id AND id = :note_id", $note);
|
||||
|
||||
$this->add_history(1, $note['id'], $note['image_id'], $note['x1'], $note['y1'], $note['height'], $note['width'], $note['note']);
|
||||
$this->add_history(1, $note['note_id'], $note['image_id'], $note['x1'], $note['y1'], $note['height'], $note['width'], $note['note']);
|
||||
}
|
||||
|
||||
private function delete_note()
|
||||
{
|
||||
global $user, $database;
|
||||
|
||||
$imageID = int_escape($_POST["image_id"]);
|
||||
$noteID = int_escape($_POST["note_id"]);
|
||||
|
||||
// validate parameters
|
||||
if (is_null($imageID) || !is_numeric($imageID) || is_null($noteID) || !is_numeric($noteID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$note = json_decode(file_get_contents('php://input'), true);
|
||||
$database->execute("
|
||||
UPDATE notes SET enable = :enable
|
||||
WHERE image_id = :image_id AND id = :id
|
||||
", ['enable' => 0, 'image_id' => $imageID, 'id' => $noteID]);
|
||||
", ['enable' => 0, 'image_id' => $note["image_id"], 'id' => $note["note_id"]]);
|
||||
|
||||
log_info("notes", "Note deleted {$noteID} by {$user->name}");
|
||||
log_info("notes", "Note deleted {$note["note_id"]} by {$user->name}");
|
||||
}
|
||||
|
||||
private function nuke_notes()
|
||||
|
|
|
@ -1,81 +1,274 @@
|
|||
/*jshint bitwise:true, curly:true, forin:false, noarg:true, noempty:true, nonew:true, undef:true, strict:false, browser:true, jquery:true */
|
||||
let notesContainer = null;
|
||||
let noteImage = document.getElementById('main_image');
|
||||
let noteBeingEdited = null;
|
||||
let dragStart = null;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if(window.notes) {
|
||||
$('#main_image').load(function(){
|
||||
$('#main_image').imgNotes({notes: window.notes});
|
||||
if(noteImage.complete) {
|
||||
renderNotes();
|
||||
} else {
|
||||
noteImage.addEventListener('load', () => {
|
||||
renderNotes();
|
||||
});
|
||||
}
|
||||
|
||||
//Make sure notes are always shown
|
||||
$('#main_image').off('mouseenter mouseleave');
|
||||
let resizeObserver = new ResizeObserver(entries => {
|
||||
renderNotes();
|
||||
});
|
||||
resizeObserver.observe(noteImage);
|
||||
}
|
||||
});
|
||||
|
||||
function renderNotes() {
|
||||
// reset the DOM to empty
|
||||
if(notesContainer) {
|
||||
notesContainer.remove();
|
||||
}
|
||||
|
||||
$('#cancelnote').click(function(){
|
||||
$('#main_image').imgAreaSelect({ hide: true });
|
||||
$('#noteform').hide();
|
||||
// check the image we're adding notes on top of
|
||||
let br = noteImage.getBoundingClientRect();
|
||||
let scale = br.width / noteImage.getAttribute("data-width");
|
||||
|
||||
// render a container full of notes
|
||||
notesContainer = document.createElement('div');
|
||||
notesContainer.className = 'notes-container';
|
||||
notesContainer.style.left = window.scrollX + br.left + 'px';
|
||||
notesContainer.style.top = window.scrollY + br.top + 'px';
|
||||
notesContainer.style.width = br.width + 'px';
|
||||
notesContainer.style.height = br.height + 'px';
|
||||
|
||||
// render each note
|
||||
window.notes.forEach(note => {
|
||||
let noteDiv = document.createElement('div');
|
||||
noteDiv.classList.add('note');
|
||||
noteDiv.style.left = note.x1 * scale + 'px';
|
||||
noteDiv.style.top = note.y1 * scale + 'px';
|
||||
noteDiv.style.width = note.width * scale + 'px';
|
||||
noteDiv.style.height = note.height * scale + 'px';
|
||||
let text = document.createElement('div');
|
||||
text.innerText = note.note;
|
||||
noteDiv.addEventListener('click', (e) => {
|
||||
noteBeingEdited = note.note_id;
|
||||
renderNotes();
|
||||
});
|
||||
noteDiv.appendChild(text);
|
||||
notesContainer.appendChild(noteDiv);
|
||||
|
||||
// if the current note is being edited, render the editor
|
||||
if(note.note_id == noteBeingEdited) {
|
||||
let editor = renderEditor(noteDiv, note);
|
||||
notesContainer.appendChild(editor);
|
||||
}
|
||||
});
|
||||
|
||||
$('#EditCancelNote').click(function() {
|
||||
$('#main_image').imgAreaSelect({ hide: true });
|
||||
$('#noteEditForm').hide();
|
||||
});
|
||||
|
||||
$('#addnote').click(function(){
|
||||
$('#noteEditForm').hide();
|
||||
$('#main_image').imgAreaSelect({ onSelectChange: showaddnote, x1: 120, y1: 90, x2: 280, y2: 210 });
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.note').click(function() {
|
||||
$('#noteform').hide();
|
||||
var imgOffset = $('#main_image').offset();
|
||||
|
||||
var x1 = parseInt(this.style.left) - imgOffset.left;
|
||||
var y1 = parseInt(this.style.top) - imgOffset.top;
|
||||
var width = parseInt(this.style.width);
|
||||
var height = parseInt(this.style.height);
|
||||
var text = $(this).next('.notep').text().replace(/([^>]?)\\n{2}/g, '$1\\n');
|
||||
var id = $(this).next('.notep').next('.noteID').text();
|
||||
|
||||
$('#main_image').imgAreaSelect({ onSelectChange: showeditnote, x1: x1, y1: y1, x2: x1 + width, y2: y1 + height });
|
||||
setEditNoteData(x1, y1, width, height, text, id);
|
||||
});
|
||||
});
|
||||
|
||||
function showaddnote (img, area) {
|
||||
var imgOffset = $(img).offset();
|
||||
var form_left = parseInt(imgOffset.left) + parseInt(area.x1);
|
||||
var form_top = parseInt(imgOffset.top) + parseInt(area.y1) + parseInt(area.height)+5;
|
||||
|
||||
$('#noteform').css({ left: form_left + 'px', top: form_top + 'px'});
|
||||
$('#noteform').show();
|
||||
$('#noteform').css('z-index', 10000);
|
||||
$('#NoteX1').val(area.x1);
|
||||
$('#NoteY1').val(area.y1);
|
||||
$('#NoteHeight').val(area.height);
|
||||
$('#NoteWidth').val(area.width);
|
||||
noteImage.parentNode.appendChild(notesContainer);
|
||||
}
|
||||
|
||||
function showeditnote (img, area) {
|
||||
var imgOffset = $(img).offset();
|
||||
var form_left = parseInt(imgOffset.left) + area.x1;
|
||||
var form_top = parseInt(imgOffset.top) + area.y2;
|
||||
/**
|
||||
*
|
||||
* @param {HTMLElement} noteDiv
|
||||
* @param {*} note
|
||||
* @returns
|
||||
*/
|
||||
function renderEditor(noteDiv, note) {
|
||||
// check the image we're adding notes on top of
|
||||
let br = noteImage.getBoundingClientRect();
|
||||
let scale = br.width / noteImage.getAttribute("data-width");
|
||||
|
||||
$('#noteEditForm').css({ left: form_left + 'px', top: form_top + 'px'});
|
||||
$('#noteEditForm').show();
|
||||
$('#noteEditForm').css('z-index', 10000);
|
||||
$('#EditNoteX1').val(area.x1);
|
||||
$('#EditNoteY1').val(area.y1);
|
||||
$('#EditNoteHeight').val(area.height);
|
||||
$('#EditNoteWidth').val(area.width);
|
||||
// set the note itself into drag & resize mode
|
||||
// NOTE: to avoid re-rendering the whole DOM every time the mouse
|
||||
// moves, we directly edit the style of the noteDiv, and then when
|
||||
// the mouse is released, we update the note object and re-render
|
||||
noteDiv.classList.add('editing');
|
||||
noteDiv.addEventListener('mousedown', (e) => {
|
||||
dragStart = {
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
mode: getArea(e.offsetX, e.offsetY, noteDiv.offsetWidth, noteDiv.offsetHeight),
|
||||
};
|
||||
noteDiv.classList.add("dragging");
|
||||
});
|
||||
noteDiv.addEventListener('mousemove', (e) => {
|
||||
if(dragStart) {
|
||||
if(dragStart.mode == "c") {
|
||||
noteDiv.style.left = (note.x1 * scale) + (e.pageX - dragStart.x) + 'px';
|
||||
noteDiv.style.top = (note.y1 * scale) + (e.pageY - dragStart.y) + 'px';
|
||||
}
|
||||
if(dragStart.mode.indexOf("n") >= 0) {
|
||||
noteDiv.style.top = (note.y1 * scale) + (e.pageY - dragStart.y) + 'px';
|
||||
noteDiv.style.height = (note.height * scale) - (e.pageY - dragStart.y) + 'px';
|
||||
}
|
||||
if(dragStart.mode.indexOf("s") >= 0) {
|
||||
noteDiv.style.height = (note.height * scale) + (e.pageY - dragStart.y) + 'px';
|
||||
}
|
||||
if(dragStart.mode.indexOf("w") >= 0) {
|
||||
noteDiv.style.left = (note.x1 * scale) + (e.pageX - dragStart.x) + 'px';
|
||||
noteDiv.style.width = (note.width * scale) - (e.pageX - dragStart.x) + 'px';
|
||||
}
|
||||
if(dragStart.mode.indexOf("e") >= 0) {
|
||||
noteDiv.style.width = (note.width * scale) + (e.pageX - dragStart.x) + 'px';
|
||||
}
|
||||
} else {
|
||||
let area = getArea(e.offsetX, e.offsetY, noteDiv.offsetWidth, noteDiv.offsetHeight);
|
||||
if(area == "c") {
|
||||
noteDiv.style.cursor = 'move';
|
||||
} else {
|
||||
noteDiv.style.cursor = area + '-resize';
|
||||
}
|
||||
}
|
||||
});
|
||||
function _commit() {
|
||||
noteDiv.classList.remove("dragging");
|
||||
dragStart = null;
|
||||
note.x1 = noteDiv.offsetLeft / scale;
|
||||
note.y1 = noteDiv.offsetTop / scale;
|
||||
note.width = noteDiv.offsetWidth / scale;
|
||||
note.height = noteDiv.offsetHeight / scale;
|
||||
renderNotes();
|
||||
}
|
||||
noteDiv.addEventListener('mouseup', _commit);
|
||||
noteDiv.addEventListener('mouseleave', _commit);
|
||||
|
||||
// add textarea / save / cancel / delete buttons
|
||||
let editor = document.createElement('div');
|
||||
editor.classList.add('editor');
|
||||
editor.style.left = note.x1 * scale + 'px';
|
||||
editor.style.top = (note.y1 + note.height) * scale + 'px';
|
||||
|
||||
let textarea = document.createElement('textarea');
|
||||
textarea.value = note.note;
|
||||
textarea.addEventListener('input', () => {
|
||||
note.note = textarea.value;
|
||||
});
|
||||
editor.appendChild(textarea);
|
||||
|
||||
let save = document.createElement('button');
|
||||
save.innerText = 'Save';
|
||||
save.addEventListener('click', () => {
|
||||
if(note.note_id == null) {
|
||||
fetch('/note/create_note', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(note)
|
||||
}).then(response => {
|
||||
if(response.ok) {
|
||||
return response.json();
|
||||
} else {
|
||||
throw new Error('Failed to create note');
|
||||
}
|
||||
}).then(data => {
|
||||
note.note_id = data.note_id;
|
||||
renderNotes();
|
||||
}).catch(error => {
|
||||
alert(error);
|
||||
});
|
||||
} else {
|
||||
fetch('/note/update_note', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(note)
|
||||
}).then(response => {
|
||||
if(!response.ok) {
|
||||
throw new Error('Failed to update note');
|
||||
}
|
||||
}).catch(error => {
|
||||
alert(error);
|
||||
});
|
||||
}
|
||||
noteBeingEdited = null;
|
||||
renderNotes();
|
||||
});
|
||||
editor.appendChild(save);
|
||||
|
||||
let cancel = document.createElement('button');
|
||||
cancel.innerText = 'Cancel';
|
||||
cancel.addEventListener('click', () => {
|
||||
noteBeingEdited = null;
|
||||
if(note.note_id == null) {
|
||||
// delete the un-saved note
|
||||
window.notes = window.notes.filter(n => n.note_id != null);
|
||||
}
|
||||
renderNotes();
|
||||
});
|
||||
editor.appendChild(cancel);
|
||||
|
||||
if(window.notes_admin && note.note_id != null) {
|
||||
let deleteNote = document.createElement('button');
|
||||
deleteNote.innerText = 'Delete';
|
||||
deleteNote.addEventListener('click', () => {
|
||||
// TODO: delete note from server
|
||||
fetch('/note/delete_note', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(note)
|
||||
}).then(response => {
|
||||
if(!response.ok) {
|
||||
throw new Error('Failed to delete note');
|
||||
}
|
||||
}).catch(error => {
|
||||
alert(error);
|
||||
});
|
||||
noteBeingEdited = null;
|
||||
window.notes = window.notes.filter(n => n.note_id != note.note_id);
|
||||
renderNotes();
|
||||
});
|
||||
editor.appendChild(deleteNote);
|
||||
}
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
function setEditNoteData(x1, y1, width, height, text, id) {
|
||||
$('#EditNoteX1').val(x1);
|
||||
$('#EditNoteY1').val(y1);
|
||||
$('#EditNoteHeight').val(height);
|
||||
$('#EditNoteWidth').val(width);
|
||||
$('#EditNoteNote').text(text);
|
||||
$('#EditNoteID').val(id);
|
||||
$('#DeleteNoteNoteID').val(id);
|
||||
function addNewNote() {
|
||||
if(window.notes.filter(note => note.note_id == null).length > 0) {
|
||||
alert("Please save all notes before adding a new one.");
|
||||
return;
|
||||
}
|
||||
window.notes.push(
|
||||
{
|
||||
x1: 10,
|
||||
y1: 10,
|
||||
width: 100,
|
||||
height: 40,
|
||||
note: "new note",
|
||||
note_id: null,
|
||||
image_id: window.notes_image_id,
|
||||
}
|
||||
);
|
||||
noteBeingEdited = null;
|
||||
renderNotes();
|
||||
}
|
||||
|
||||
function getArea(x, y, width, height) {
|
||||
let border = 10;
|
||||
|
||||
if(y < border) {
|
||||
if(x < border) {
|
||||
return "nw";
|
||||
} else if(x > width - border) {
|
||||
return "ne";
|
||||
} else {
|
||||
return "n";
|
||||
}
|
||||
} else if(y > height - border) {
|
||||
if(x < border) {
|
||||
return "sw";
|
||||
} else if(x > width - border) {
|
||||
return "se";
|
||||
} else {
|
||||
return "s";
|
||||
}
|
||||
} else if(x < border) {
|
||||
return "w";
|
||||
} else if(x > width - border) {
|
||||
return "e";
|
||||
} else {
|
||||
return "c";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,87 +1,57 @@
|
|||
.note {
|
||||
display: block;
|
||||
.notes-container {
|
||||
position: absolute;
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
.notes-container .note {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: black;
|
||||
background-color: #FFE;
|
||||
border: 1px dashed black;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
|
||||
filter:alpha(opacity=50);
|
||||
-moz-opacity:0.5;
|
||||
-khtml-opacity: 0.5;
|
||||
opacity: 0.5;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.notep {
|
||||
display: none;
|
||||
color: #412a21;
|
||||
background-color: #fffdef;
|
||||
border: #412a21 1px solid;
|
||||
font-size: 8pt;
|
||||
margin-top: 0;
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
width: 175px;
|
||||
.notes-container .note.editing {
|
||||
opacity: 1;
|
||||
border: 1px dashed red;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#noteform, #noteEditForm {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
#noteform textarea, #noteEditForm textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
* imgAreaSelect default style
|
||||
*/
|
||||
|
||||
.imgareaselect-border1 {
|
||||
background: url(border-v.gif) repeat-y left top;
|
||||
}
|
||||
|
||||
.imgareaselect-border2 {
|
||||
background: url(border-h.gif) repeat-x left top;
|
||||
}
|
||||
|
||||
.imgareaselect-border3 {
|
||||
background: url(border-v.gif) repeat-y right top;
|
||||
}
|
||||
|
||||
.imgareaselect-border4 {
|
||||
background: url(border-h.gif) repeat-x left bottom;
|
||||
}
|
||||
|
||||
.imgareaselect-border1, .imgareaselect-border2,
|
||||
.imgareaselect-border3, .imgareaselect-border4 {
|
||||
filter: alpha(opacity=50);
|
||||
.notes-container .note.editing.dragging {
|
||||
opacity: 0.5;
|
||||
z-index: 2;
|
||||
}
|
||||
.notes-container .note:hover {
|
||||
opacity: 1;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.imgareaselect-handle {
|
||||
background-color: #fff;
|
||||
border: solid 1px #000;
|
||||
filter: alpha(opacity=50);
|
||||
opacity: 0.5;
|
||||
.notes-container .editor {
|
||||
display: grid;
|
||||
color: black;
|
||||
background-color: #EFE;
|
||||
border: 1px dashed blue;
|
||||
position: absolute;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-areas:
|
||||
"text text"
|
||||
"save cancel"
|
||||
"delete delete";
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.imgareaselect-outer {
|
||||
/*background-color: #000;*/
|
||||
filter: alpha(opacity=50);
|
||||
opacity: 0.5;
|
||||
.notes-container .editor TEXTAREA {
|
||||
grid-area: text;
|
||||
// resize: none;
|
||||
}
|
||||
|
||||
.imgareaselect-selection {
|
||||
.notes-container .editor BUTTON[value="Save"] {
|
||||
grid-area: save;
|
||||
}
|
||||
|
||||
/* Makes sure the note block is hidden */
|
||||
section#note_system {
|
||||
height: 0;
|
||||
.notes-container .editor BUTTON[value="Cancel"] {
|
||||
grid-area: cancel;
|
||||
}
|
||||
section#note_system > .blockbody {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
.notes-container .editor BUTTON[value="Delete"] {
|
||||
grid-area: delete;
|
||||
}
|
||||
|
|
|
@ -4,41 +4,38 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shimmie2;
|
||||
|
||||
use MicroHTML\HTMLElement;
|
||||
use function MicroHTML\INPUT;
|
||||
|
||||
class NotesTheme extends Themelet
|
||||
{
|
||||
public function note_button(int $image_id): string
|
||||
public function note_button(int $image_id): HTMLElement
|
||||
{
|
||||
return '
|
||||
<!-- <a href="#" id="addnotelink" >Add a note</a> -->
|
||||
<form action="" method="">
|
||||
<input type="button" id="addnote" value="Add Note">
|
||||
<input type="hidden" name="image_id" value="'.$image_id.'">
|
||||
</form>
|
||||
';
|
||||
return SHM_SIMPLE_FORM("", INPUT(["type"=>"button", "value"=>"Add Note", "onclick"=>"addNewNote()"]));
|
||||
}
|
||||
public function request_button(int $image_id): string
|
||||
public function request_button(int $image_id): HTMLElement
|
||||
{
|
||||
return make_form(make_link("note/add_request")) . '
|
||||
<input id="noterequest" type="submit" value="Add Note Request">
|
||||
<input type="hidden" name="image_id" value="'.$image_id.'">
|
||||
</form>
|
||||
';
|
||||
return SHM_SIMPLE_FORM(
|
||||
"note/add_request",
|
||||
INPUT(["type"=>"hidden", "name"=>"image_id", "value"=>$image_id]),
|
||||
INPUT(["type"=>"submit", "value"=>"Add Note Request"]),
|
||||
);
|
||||
}
|
||||
public function nuke_notes_button(int $image_id): string
|
||||
public function nuke_notes_button(int $image_id): HTMLElement
|
||||
{
|
||||
return make_form(make_link("note/nuke_notes")) . '
|
||||
<input id="noterequest" type="submit" value="Nuke Notes" onclick="return confirm_action(\'Are you sure?\')">
|
||||
<input type="hidden" name="image_id" value="'.$image_id.'">
|
||||
</form>
|
||||
';
|
||||
return SHM_SIMPLE_FORM(
|
||||
"note/nuke_notes",
|
||||
INPUT(["type"=>"hidden", "name"=>"image_id", "value"=>$image_id]),
|
||||
INPUT(["type"=>"submit", "value"=>"Nuke Notes", "onclick"=>"return confirm_action('Are you sure?')"]),
|
||||
);
|
||||
}
|
||||
public function nuke_requests_button(int $image_id): string
|
||||
public function nuke_requests_button(int $image_id): HTMLElement
|
||||
{
|
||||
return make_form(make_link("note/nuke_requests")) . '
|
||||
<input id="noterequest" type="submit" value="Nuke Requests" onclick="return confirm_action()">
|
||||
<input type="hidden" name="image_id" value="'.$image_id.'">
|
||||
</form>
|
||||
';
|
||||
return SHM_SIMPLE_FORM(
|
||||
"note/nuke_requests",
|
||||
INPUT(["type"=>"hidden", "name"=>"image_id", "value"=>$image_id]),
|
||||
INPUT(["type"=>"submit", "value"=>"Nuke Requests", "onclick"=>"return confirm_action('Are you sure?')"]),
|
||||
);
|
||||
}
|
||||
|
||||
public function search_notes_page(Page $page): void
|
||||
|
@ -56,91 +53,23 @@ class NotesTheme extends Themelet
|
|||
// check action POST on form
|
||||
public function display_note_system(Page $page, int $image_id, array $recovered_notes, bool $adminOptions): void
|
||||
{
|
||||
$base_href = get_base_href();
|
||||
|
||||
$page->add_html_header("<script defer src='$base_href/ext/notes/lib/jquery.imgnotes-1.0.min.js' type='text/javascript'></script>");
|
||||
$page->add_html_header("<script defer src='$base_href/ext/notes/lib/jquery.imgareaselect-1.0.0-rc1.min.js' type='text/javascript'></script>");
|
||||
$page->add_html_header("<link rel='stylesheet' type='text/css' href='$base_href/ext/notes/lib/jquery.imgnotes-1.0.min.css' />");
|
||||
|
||||
$to_json = [];
|
||||
foreach ($recovered_notes as $note) {
|
||||
$parsedNote = $note["note"];
|
||||
$parsedNote = str_replace("\n", "\\n", $parsedNote);
|
||||
$parsedNote = str_replace("\r", "\\r", $parsedNote);
|
||||
|
||||
$to_json[] = [
|
||||
'image_id' => $image_id,
|
||||
'x1' => $note["x1"],
|
||||
'y1' => $note["y1"],
|
||||
'height' => $note["height"],
|
||||
'width' => $note["width"],
|
||||
'note' => $parsedNote,
|
||||
'note' => $note["note"],
|
||||
'note_id' => $note["id"],
|
||||
];
|
||||
}
|
||||
|
||||
$html = "<script type='text/javascript'>notes = ".json_encode($to_json)."</script>";
|
||||
|
||||
$html .= "
|
||||
<div id='noteform'>
|
||||
".make_form(make_link("note/add_note"))."
|
||||
<input type='hidden' name='image_id' value='".$image_id."' />
|
||||
<input name='note_x1' type='hidden' value='' id='NoteX1' />
|
||||
<input name='note_y1' type='hidden' value='' id='NoteY1' />
|
||||
<input name='note_height' type='hidden' value='' id='NoteHeight' />
|
||||
<input name='note_width' type='hidden' value='' id='NoteWidth' />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan='2'>
|
||||
<textarea name='note_text' id='NoteNote' ></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type='submit' value='Add Note' /></td>
|
||||
<td><input type='button' value='Cancel' id='cancelnote' /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div id='noteEditForm'>
|
||||
".make_form(make_link("note/edit_note"))."
|
||||
<input type='hidden' name='image_id' value='".$image_id."' />
|
||||
<input type='hidden' name='note_id' id='EditNoteID' value='' />
|
||||
<input name='note_x1' type='hidden' value='' id='EditNoteX1' />
|
||||
<input name='note_y1' type='hidden' value='' id='EditNoteY1' />
|
||||
<input name='note_height' type='hidden' value='' id='EditNoteHeight' />
|
||||
<input name='note_width' type='hidden' value='' id='EditNoteWidth' />
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan='2'>
|
||||
<textarea name='note_text' id='EditNoteNote' ></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type='submit' value='Save Note' /></td>
|
||||
<td><input type='button' value='Cancel' id='EditCancelNote' /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>";
|
||||
|
||||
if ($adminOptions) {
|
||||
$html .= "
|
||||
".make_form(make_link("note/delete_note"))."
|
||||
<input type='hidden' name='image_id' value='".$image_id."' />
|
||||
<input type='hidden' name='note_id' value='' id='DeleteNoteNoteID' />
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type='submit' value='Delete note' /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
";
|
||||
}
|
||||
|
||||
$html .= "</div>";
|
||||
|
||||
$page->add_block(new Block(null, $html, "main", 1, 'note_system'));
|
||||
$page->add_html_header("<script type='text/javascript'>
|
||||
window.notes = ".json_encode($to_json).";
|
||||
window.notes_image_id = $image_id;
|
||||
window.notes_admin = ".($adminOptions ? "true" : "false").";
|
||||
</script>");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
namespace Shimmie2;
|
||||
use MicroHTML\HTMLElement;
|
||||
|
||||
class ImageAdminBlockBuildingEvent extends Event
|
||||
{
|
||||
/** @var string[] */
|
||||
/** @var HTMLElement[]|string[] */
|
||||
public array $parts = [];
|
||||
public Image $image;
|
||||
public User $user;
|
||||
|
@ -20,7 +21,7 @@ class ImageAdminBlockBuildingEvent extends Event
|
|||
$this->context = $context;
|
||||
}
|
||||
|
||||
public function add_part(string $html, int $position = 50)
|
||||
public function add_part(HTMLElement|string $html, int $position = 50)
|
||||
{
|
||||
while (isset($this->parts[$position])) {
|
||||
$position++;
|
||||
|
|
Reference in a new issue