');
+ this.note.$note_container.append(this.$note_box);
+
+ if (note.embed) {
+ this.$note_box.addClass("embedded");
+ this.$inner_border = $('
');
+ this.$note_box.append(this.$inner_border);
}
- $note_box.data("id", String(id));
- $note_box.attr("data-id", String(id));
- $note_box.draggable({
- containment: $("#image"),
- stop: function(e, ui) {
- Note.Box.update_data_attributes($note_box);
- }
+ if (this.note.is_new()) {
+ this.$note_box.addClass("unsaved");
+ }
+
+ this.$note_box.draggable({
+ containment: this.note.$note_container,
});
- $note_box.resizable({
- containment: $("#image"),
- handles: "se, nw",
- stop: function(e, ui) {
- Note.Box.update_data_attributes($note_box);
- }
+
+ this.$note_box.resizable({
+ containment: this.note.$note_container,
+ handles: Note.RESIZE_HANDLES,
+ minWidth: Note.MIN_NOTE_SIZE,
+ minHeight: Note.MIN_NOTE_SIZE,
});
- $note_box.css({position: "absolute"});
- $note_box.append($inner_border);
- Note.Box.bind_events($note_box);
- return $note_box;
- },
+ this.$note_box.on("click.danbooru", this.on_click.bind(this));
+ this.$note_box.on("mouseenter.danbooru", this.on_mouseenter.bind(this));
+ this.$note_box.on("mouseleave.danbooru", this.on_mouseleave.bind(this));
+ this.$note_box.on("dragstart.danbooru resizestart.danbooru", this.on_dragstart.bind(this));
+ this.$note_box.on("dragstop.danbooru resizestop.danbooru", this.on_dragstop.bind(this));
+ }
- update_data_attributes: function($note_box) {
- var $image = $("#image");
- var ratio = $image.width() / parseFloat($image.data("original-width"));
- var new_x = parseFloat($note_box.css("left"));
- var new_y = parseFloat($note_box.css("top"));
- var new_width = parseFloat($note_box.css("width"));
- var new_height = parseFloat($note_box.css("height"));
- new_x = parseInt(new_x / ratio);
- new_y = parseInt(new_y / ratio);
- new_width = parseInt(new_width / ratio);
- new_height = parseInt(new_height / ratio);
- $note_box.data("x", new_x);
- $note_box.data("y", new_y);
- $note_box.data("width", new_width);
- $note_box.data("height", new_height);
- },
+ on_click() {
+ if (!Utility.test_max_width(660)) {
+ // Toggle selection status when note is clicked. Enable movement keys when note is selected.
+ if (this.$note_box.hasClass("movable")) {
+ this.$note_box.removeClass("movable");
+ $(document).off("keydown.nudge_note");
+ $(document).off("keydown.resize_note");
+ } else {
+ this.$note_box.addClass("movable");
+ Utility.keydown("up down left right", "nudge_note", this.key_nudge.bind(this));
+ Utility.keydown("shift+up shift+down shift+left shift+right", "resize_note", this.key_resize.bind(this));
+ }
+ } else if (this.$note_box.hasClass("viewing")) {
+ this.note.body.hide();
+ this.$note_box.removeClass("viewing");
+ } else {
+ $(".note-box").removeClass("viewing");
+ this.note.body.show();
+ this.$note_box.addClass("viewing");
+ }
+ }
- copy_style_attributes: function($note_box) {
- const $attribute_child = $note_box.find('.note-box-attributes');
+ on_mouseenter() {
+ this.note.body.show();
+ this.$note_box.addClass("hovering");
+ }
+
+ on_mouseleave() {
+ this.note.body.hide();
+ this.$note_box.removeClass("hovering");
+ }
+
+ on_dragstart() {
+ this.$note_box.addClass("unsaved");
+ Note.Body.hide_all();
+ }
+
+ // Reset the note box placement after the box is dragged or resized. Dragging the note
+ // changes the CSS coordinates to pixels, so we have to convert them back to percentages.
+ on_dragstop() {
+ this.place_note(this.note.x, this.note.y, this.note.width, this.note.height);
+ }
+
+ // Place the note box using absolute percentage coordinates (floats in the range 0.0..1.0).
+ place_note(x, y, w, h) {
+ if (this.note.embed && this.note.has_rotation) {
+ let position = this.get_min_max_position();
+ x = position.norm_left / this.note.image_width;
+ y = position.norm_top / this.note.image_height;
+ }
+
+ x = clamp(x, 0.0, 1.0);
+ y = clamp(y, 0.0, 1.0);
+ w = clamp(w, Note.MIN_NOTE_SIZE / this.note.post_width, 1.0);
+ h = clamp(h, Note.MIN_NOTE_SIZE / this.note.post_height, 1.0);
+
+ this.$note_box.css({
+ top: (100 * y) + '%',
+ left: (100 * x) + '%',
+ width: (100 * w) + '%',
+ height: (100 * h) + '%',
+ });
+ }
+
+ copy_style_attributes() {
+ let $note_box = this.$note_box;
+ let $attribute_child = $note_box.find('.note-box-attributes');
let has_rotation = false;
+
Note.COPY_ATTRIBUTES.forEach((attribute)=>{
- const attribute_value = Note.permitted_style_values(attribute, $attribute_child);
+ const attribute_value = this.permitted_style_values(attribute, $attribute_child);
$note_box.css(attribute, attribute_value);
+
if (attribute === "transform" && attribute_value.startsWith("rotate")) {
has_rotation = true;
}
});
+
if (has_rotation) {
const current_left = Math.round(parseFloat($note_box.css("left")));
const current_top = Math.round(parseFloat($note_box.css("top")));
- const position = Note.Box.get_min_max_position($note_box);
+ const position = this.get_min_max_position();
+
// Checks for the scenario where the user sets invalid box values through the API
// or by adjusting the box dimensions through the browser's dev console before saving
if (current_left !== position.norm_left || current_top !== position.norm_top) {
@@ -97,135 +152,48 @@ let Note = {
top: position.percent_top,
left: position.percent_left,
});
+
$note_box.addClass("out-of-bounds");
} else {
$note_box.removeClass("out-of-bounds");
}
- $note_box.data('has_rotation', true);
+
+ this.note.has_rotation = true;
} else {
- $note_box.data('has_rotation', false);
+ this.note.has_rotation = false;
}
- },
+ }
- bind_events: function($note_box) {
- $note_box.on(
- "dragstart.danbooru resizestart.danbooru",
- function(e) {
- var $note_box_inner = $(e.currentTarget);
- $note_box_inner.addClass("unsaved");
- Note.dragging = true;
- Note.clear_timeouts();
- Note.Body.hide_all();
- e.stopPropagation();
- }
- );
-
- $note_box.on(
- "dragstop.danbooru resizestop.danbooru",
- function(e) {
- Note.dragging = false;
- e.stopPropagation();
- }
- );
-
- $note_box.on(
- "mouseover.danbooru mouseout.danbooru",
- function(e) {
- if (Note.dragging || Utility.test_max_width(660)) {
- return;
- }
-
- var $this = $(this);
- var $note_box_inner = $(e.currentTarget);
-
- const note_id = $note_box_inner.data("id");
- if (e.type === "mouseover") {
- Note.Body.show(note_id);
- if (Note.editing) {
- $this.resizable("enable");
- $this.draggable("enable");
- }
- $note_box.addClass("hovering");
- } else if (e.type === "mouseout") {
- Note.Body.hide(note_id);
- if (Note.editing) {
- $this.resizable("disable");
- $this.draggable("disable");
- }
- $note_box.removeClass("hovering");
- }
-
- e.stopPropagation();
- }
- );
-
- $note_box.on(
- "click.danbooru",
- function (event) {
- const note_id = $note_box.data("id");
- if (!Utility.test_max_width(660)) {
- $(".note-box").removeClass("movable");
- if (note_id === Note.move_id) {
- Note.move_id = null;
- } else {
- Note.move_id = note_id;
- $note_box.addClass("movable");
- }
- } else if ($note_box.hasClass("viewing")) {
- Note.Body.hide(note_id);
- $note_box.removeClass("viewing");
- } else {
- $(".note-box").removeClass("viewing");
- Note.Body.show(note_id);
- $note_box.addClass("viewing");
- }
- }
- );
-
- $note_box.on("mousedown.danbooru", function(event) {
- Note.drag_id = $note_box.data('id');
- });
-
- $note_box.on("mouseup.danbooru.drag", Note.Box.drag_stop);
- },
-
- find: function(id) {
- return $(".note-container div.note-box[data-id=" + id + "]");
- },
-
- drag_stop: function(event) {
- if (Note.drag_id !== null) {
- const $image = $("#image");
- const $note_box = Note.Box.find(Note.drag_id);
- const dimensions = {
- top: (100 * ($note_box.position().top / $image.height())) + '%',
- left: (100 * ($note_box.position().left / $image.width())) + '%',
- height: (100 * ($note_box.height() / $image.height())) + '%',
- width: (100 * ($note_box.width() / $image.width())) + '%',
- };
- if (Note.embed && $note_box.data('has_rotation')) {
- const position = Note.Box.get_min_max_position($note_box);
- Object.assign(dimensions, {
- top: position.percentage_top,
- left: position.percentage_left,
- });
- }
- $note_box.css(dimensions);
- Note.drag_id = null;
+ permitted_style_values(attribute, $attribute_child) {
+ if ($attribute_child.length === 0) {
+ return "";
}
- },
- key_nudge: function(event) {
- if (!Note.move_id) {
- return;
+ let found_attribute = $attribute_child.attr('style').split(';').filter(val => val.match(RegExp(`(^| )${attribute}:`)));
+ if (found_attribute.length === 0) {
+ return "";
}
- const $note_box = Note.Box.find(Note.move_id);
- if ($note_box.length === 0) {
- return;
+
+ let [, value] = found_attribute[0].trim().split(':').map(val => val.trim());
+ if (attribute === "background-color") {
+ const color_code = $attribute_child.css('background-color');
+ return color_code.startsWith('rgba') ? "" : value;
}
- let computed_style = window.getComputedStyle($note_box[0]);
- let current_top = Math.round(parseFloat(computed_style.top));
- let current_left = Math.round(parseFloat(computed_style.left));
+
+ if (attribute === "transform") {
+ let rotate_match = value.match(/rotate\([^)]+\)/);
+ return rotate_match ? rotate_match[0] : "";
+ }
+
+ return value;
+ }
+
+ key_nudge(event) {
+ let $note_box = this.note.box.$note_box;
+
+ let current_top = Math.round($note_box.position().top);
+ let current_left = Math.round($note_box.position().left);
+
switch (event.originalEvent.key) {
case "ArrowUp":
current_top--;
@@ -242,28 +210,25 @@ let Note = {
default:
// do nothing
}
- let position = Note.Box.get_min_max_position($note_box, current_top, current_left);
+
+ let position = this.get_min_max_position(current_top, current_left);
$note_box.css({
top: position.percent_top,
left: position.percent_left,
});
+
$note_box.addClass("unsaved");
event.preventDefault();
- },
+ }
- key_resize: function (event) {
- if (!Note.move_id) {
- return;
- }
- const $note_box = Note.Box.find(Note.move_id);
- if ($note_box.length === 0) {
- return;
- }
- let computed_style = window.getComputedStyle($note_box[0]);
- let current_top = Math.round(parseFloat(computed_style.top));
- let current_left = Math.round(parseFloat(computed_style.left));
+ key_resize(event) {
+ let $note_box = this.note.box.$note_box;
+
+ let current_top = Math.round($note_box.position().top);
+ let current_left = Math.round($note_box.position().left);
let current_height = $note_box.height();
let current_width = $note_box.width();
+
switch (event.originalEvent.key) {
case "ArrowUp":
current_height--;
@@ -280,27 +245,32 @@ let Note = {
default:
// do nothing
}
- const position = Note.Box.get_min_max_position($note_box, null, null, current_height, current_width);
+
+ const position = this.get_min_max_position(null, null, current_height, current_width);
if (current_top === position.norm_top && current_left === position.norm_left) {
$note_box.css({
height: current_height,
width: current_width,
});
}
+
$note_box.addClass("unsaved");
event.preventDefault();
- },
+ }
- get_min_max_position: function($note_box, current_top = null, current_left = null, current_height = null, current_width = null) {
+ get_min_max_position(current_top = null, current_left = null, current_height = null, current_width = null) {
+ let $note_box = this.$note_box;
const computed_style = window.getComputedStyle($note_box[0]);
+
current_top = (current_top === null ? parseFloat(computed_style.top) : current_top);
current_left = (current_left === null ? parseFloat(computed_style.left) : current_left);
current_height = current_height || $note_box.height();
current_width = current_width || $note_box.width();
- const $image = $("#image");
- const image_height = $image.height();
- const image_width = $image.width();
- const box_data = Note.Box.get_bounding_box($note_box, current_height, current_width);
+
+ const image_height = this.note.image_height;
+ const image_width = this.note.image_width;
+ const box_data = this.get_bounding_box(current_height, current_width);
+
if (((box_data.max_x - box_data.min_x) <= image_width) && ((box_data.max_y - box_data.min_y) <= image_height)) {
current_top = Math.min(Math.max(current_top, -box_data.min_y, 0), image_height - box_data.max_y - 2, image_height - box_data.min_y - box_data.max_y - 2, image_height);
current_left = Math.min(Math.max(current_left, -box_data.min_x, 0), image_width - box_data.max_x - 2, image_width - box_data.min_x - box_data.max_x - 2, image_width);
@@ -308,20 +278,23 @@ let Note = {
Utility.error("Box too large to be rotated!");
$note_box.css('transform', 'none');
}
+
return {
norm_top: Math.round(current_top),
norm_left: Math.round(current_left),
- percent_top: (100 * (current_top / $image.height())) + '%',
- percent_left: (100 * (current_left / $image.width())) + '%',
+ percent_top: (100 * (current_top / image_height)) + '%',
+ percent_left: (100 * (current_left / image_width)) + '%',
};
- },
+ }
- get_bounding_box: function($note_box, height = null, width = null) {
+ get_bounding_box(height = null, width = null) {
+ let $note_box = this.$note_box;
height = height || $note_box.height();
width = width || $note_box.width();
let old_coord = [[0, 0], [width, 0], [0, height], [width, height]];
const computed_style = window.getComputedStyle($note_box[0]);
const match = computed_style.transform.match(/matrix\(([-e0-9.]+), ([-e0-9.]+)/);
+
if (!match) {
return {
min_x: 0,
@@ -332,6 +305,7 @@ let Note = {
degrees: 0,
}
}
+
const costheta = Math.round(match[1] * 1000) / 1000;
const sintheta = Math.round(match[2] * 1000) / 1000;
let trans_x = width / 2;
@@ -340,6 +314,7 @@ let Note = {
let max_x = 0;
let min_y = Infinity;
let max_y = 0;
+
const new_coord = old_coord.map((coord)=>{
let temp_x = coord[0] - trans_x;
let temp_y = coord[1] - trans_y;
@@ -353,11 +328,14 @@ let Note = {
max_y = Math.max(max_y, new_y);
return [new_x, new_y];
});
+
const norm_coord = new_coord.map((coord)=>{
return [coord[0] - min_x, coord[1] - min_y];
});
+
const radians_per_degree = 0.017453292519943295;
const degrees = Math.asin(sintheta) / radians_per_degree;
+
return {
min_x: min_x,
min_y: min_y,
@@ -366,72 +344,62 @@ let Note = {
norm_coord: norm_coord,
degrees: degrees,
};
- },
+ }
- show_highlighted: function($note_box) {
- var note_id = $note_box.data("id");
-
- Note.Body.show(note_id);
+ show_highlighted() {
+ this.note.body.show();
$(".note-box-highlighted").removeClass("note-box-highlighted");
- $note_box.addClass("note-box-highlighted");
- $note_box[0].scrollIntoView(false);
- },
+ this.$note_box.addClass("note-box-highlighted");
+ this.$note_box[0].scrollIntoView(false);
+ }
- scale: function($note_box) {
- var $image = $("#image");
- var original_width = $image.data("original-width");
- var original_height = $image.data("original-height");
- var x_percent = 100 * ($note_box.data('x') / original_width);
- var y_percent = 100 * ($note_box.data('y') / original_height);
- var height_percent = 100 * ($note_box.data('height') / original_height);
- var width_percent = 100 * ($note_box.data('width') / original_width);
- $note_box.css({
- top: y_percent + '%',
- left: x_percent + '%',
- width: width_percent + '%',
- height: height_percent + '%',
- });
- },
+ // Rescale font sizes of embedded notes when the image is resized.
+ static scale_all() {
+ let $image = $("#image");
+ let $container = $(".note-container");
- scale_all: function() {
- const $container = $('.note-container');
if ($container.length === 0) {
return;
}
- let $image = $("#image");
- if (Note.embed) {
- let large_width = parseFloat($image.data('large-width'));
- let ratio = $image.width() / large_width;
- let font_percentage = ratio * 100;
- $container.css('font-size', font_percentage + '%');
- }
- },
- toggle_all: function() {
+ let large_width = parseFloat($image.data('large-width'));
+ let ratio = $image.width() / large_width;
+ let font_percentage = ratio * 100;
+
+ $container.css('font-size', font_percentage + '%');
+ }
+
+ static toggle_all() {
$(".note-container").toggleClass("hide-notes");
}
- },
+ }
- Body: {
- create: function(id) {
- var $note_body = $('
');
- $note_body.addClass("note-body");
- $note_body.data("id", String(id));
- $note_body.attr("data-id", String(id));
- $note_body.hide();
- Note.Body.bind_events($note_body);
- return $note_body;
- },
+ static Body = class {
+ note = null;
+ $note_body = null;
- initialize: function($note_body) {
- var $note_box = Note.Box.find($note_body.data("id"));
- if (Note.embed && $note_box.data('has_rotation')) {
- const box_data = Note.Box.get_bounding_box($note_box);
+ constructor(note) {
+ this.note = note;
+ this.$note_body = $('
');
+ this.note.$note_container.append(this.$note_body);
+
+ this.$note_body.on("mouseover.danbooru", this.on_mouseover.bind(this));
+ this.$note_body.on("mouseout.danbooru", this.on_mouseout.bind(this));
+ this.$note_body.on("click.danbooru", this.on_click.bind(this));
+ }
+
+ initialize() {
+ let $note_body = this.$note_body;
+ let $note_box = this.note.box.$note_box;
+
+ if (this.note.embed && this.note.has_rotation) {
+ const box_data = this.note.box.get_bounding_box();
// Select the lowest box corner to the farthest left
let selected_corner = box_data.norm_coord.reduce(function (selected, coord) {return (selected[1] > coord[1]) || (selected[1] === coord[1] && selected[0] < coord[0]) ? selected : coord;});
let normalized_degrees = box_data.degrees % 90.0;
// Align to the left or right body corner depending upon the box angle
let body_corner = $note_box.position().left - (normalized_degrees > 0.0 && normalized_degrees <= 45.0 ? $note_body.width() : 0);
+
$note_body.css({
top: $note_box.position().top + selected_corner[1] + 5,
left: body_corner + selected_corner[0],
@@ -442,46 +410,47 @@ let Note = {
left: $note_box.position().left,
});
}
- Note.Body.bound_position($note_body);
- },
- bound_position: function($note_body) {
- var $image = $("#image");
+ this.bound_position();
+ }
+
+ bound_position() {
+ var $image = this.note.$note_container;
var doc_width = $image.offset().left + $image.width();
+ let $note_body = this.$note_body;
if ($note_body.offset().left + $note_body.width() > doc_width) {
$note_body.css({
left: $note_body.position().left - 10 - ($note_body.offset().left + $note_body.width() - doc_width)
});
}
- },
+ }
- show: function(id) {
+ show() {
Note.Body.hide_all();
- Note.clear_timeouts();
- var $note_body = Note.Body.find(id);
- if (!$note_body.data('resized')) {
- Note.Body.resize($note_body);
- $note_body.data('resized', 'true');
+
+ if (!this.resized) {
+ this.resize();
+ this.resized = true;
}
- $note_body.show();
- Note.Body.initialize($note_body);
- },
- find: function(id) {
- return $(".note-container div.note-body[data-id=" + id + "]");
- },
+ this.$note_body.show();
+ this.initialize();
+ }
- hide: function(id) {
- var $note_body = Note.Body.find(id);
- Note.timeouts.push(setTimeout(() => $note_body.hide(), Note.HIDE_DELAY));
- },
+ hide(delay = Note.HIDE_DELAY) {
+ Note.timeouts.push(setTimeout(() => this.$note_body.hide(), delay));
+ }
- hide_all: function() {
+ static hide_all() {
+ Note.timeouts.forEach(clearTimeout);
+ Note.timeouts = [];
$(".note-container div.note-body").hide();
- },
+ }
+
+ resize() {
+ let $note_body = this.$note_body;
- resize: function($note_body) {
$note_body.css("min-width", "");
var w = $note_body.width();
var h = $note_body.height();
@@ -525,75 +494,79 @@ let Note = {
$note_body.css("min-width", hi);
}
}
- },
+ }
+
+ display_text(text) {
+ this.set_text(text);
+
+ if (this.note.embed) {
+ let $note_inner_box = this.note.box.$inner_border;
- set_text: function($note_body, $note_box, text) {
- if (Note.embed) {
- const $note_inner_box = $note_box.find("div.note-box-inner-border");
- Note.Body.display_text($note_inner_box, text);
// Reset the font size so that the normalization calculations will be correct
- $note_inner_box.css("font-size", Note.base_font_size + "px");
- Note.normalize_sizes($note_inner_box.children(), Note.base_font_size);
+ $note_inner_box.css("font-size", this.note.base_font_size + "px");
+ this.note.normalize_sizes($note_inner_box.children(), this.note.base_font_size);
+
// Clear the font size so that the fonts will be scaled to the current value
$note_inner_box.css("font-size", "");
- Note.Box.copy_style_attributes($note_box);
- } else {
- Note.Body.display_text($note_body, text);
+ this.note.box.copy_style_attributes();
}
- Note.Body.resize($note_body);
- Note.Body.bound_position($note_body);
- },
- display_text: function($note_body, text) {
+ this.resize();
+ this.bound_position();
+ }
+
+ set_text(text) {
+ text = text ?? "";
text = text.replace(/
/g, '');
text = text.replace(/<\/tn>/g, '
');
text = text.replace(/\n/g, '
');
- $note_body.html(text);
- },
- bind_events: function($note_body) {
- $note_body.on("mouseover.danbooru", function(e) {
- var $note_body_inner = $(e.currentTarget);
- Note.Body.show($note_body_inner.data("id"));
- e.stopPropagation();
- });
-
- $note_body.on("mouseout.danbooru", function(e) {
- var $note_body_inner = $(e.currentTarget);
- Note.Body.hide($note_body_inner.data("id"));
- e.stopPropagation();
- });
-
- if (CurrentUser.data("is-anonymous") === false) {
- $note_body.on("click.danbooru", function(e) {
- if (e.target.tagName !== "A") {
- var $note_body_inner = $(e.currentTarget);
- Note.Edit.show($note_body_inner);
- }
- e.stopPropagation();
- });
+ if (this.note.embed) {
+ this.note.box.$inner_border.html(text);
+ this.$note_body.html("Click to edit");
+ } else if (text) {
+ this.$note_body.html(text);
} else {
- $note_body.on("click.danbooru", function(e) {
- if (e.target.tagName !== "A") {
- Utility.notice("You must be logged in to edit notes");
- }
- e.stopPropagation();
- });
+ this.$note_body.html("Click to edit");
}
}
- },
- Edit: {
- show: function($note_body) {
- var id = $note_body.data("id");
+ async preview_text(text) {
+ this.display_text("Loading...");
+ let response = await $.getJSON("/note_previews", { body: text });
- if (Note.editing) {
+ this.display_text(response.body);
+ this.initialize();
+ this.$note_body.show();
+ }
+
+ on_mouseover(e) {
+ this.show();
+ }
+
+ on_mouseout() {
+ this.hide();
+ }
+
+ on_click(e) {
+ // don't open the note edit dialog when the user clicks a link in the note body.
+ if ($(e.target).is("a")) {
return;
}
- $(".note-box").resizable("disable");
- $(".note-box").draggable("disable");
- $(".note-box").addClass("editing");
+ if (CurrentUser.data("is-anonymous")) {
+ Utility.notice("You must be logged in to edit notes");
+ } else {
+ Note.Edit.show(this.note);
+ }
+ }
+ }
+
+ static Edit = class {
+ static show(note) {
+ if ($(".note-box").hasClass("editing")) {
+ return;
+ }
let $textarea = $('');
$textarea.css({
@@ -602,15 +575,16 @@ let Note = {
resize: "none",
});
- if (!$note_body.hasClass("new-note")) {
- $textarea.val($note_body.data("original-body"));
+ if (!note.is_new()) {
+ $textarea.val(note.original_body);
}
let $dialog = $('');
- let note_title = (typeof id === 'string' && id.startsWith('x') ? 'Creating new note' : 'Editing note #' + id);
+ let note_title = note.is_new() ? 'Creating new note' : `Editing note #${note.id}`;
+
$dialog.append('' + note_title + ' (view help)');
$dialog.append($textarea);
- $dialog.data("id", id);
+
$dialog.dialog({
width: 360,
height: 240,
@@ -622,448 +596,321 @@ let Note = {
classes: {
"ui-dialog": "note-edit-dialog",
},
+ open: () => {
+ $(".note-box").addClass("editing");
+ },
+ close: () => {
+ $(".note-box").removeClass("editing");
+ },
buttons: {
- "Save": Note.Edit.save,
- "Preview": Note.Edit.preview,
- "Cancel": Note.Edit.cancel,
- "Delete": Note.Edit.destroy,
- "History": Note.Edit.history
+ "Save": () => Note.Edit.save($dialog, note),
+ "Preview": () => Note.Edit.preview($dialog, note),
+ "Cancel": () => Note.Edit.cancel($dialog, note),
+ "Delete": () => Note.Edit.destroy($dialog, note),
+ "History": () => Note.Edit.history($dialog, note),
}
});
- $dialog.data("uiDialog")._title = function(title) {
- title.html(this.options.title); // Allow unescaped html in dialog title
- }
-
- $dialog.on("dialogclose.danbooru", function() {
- Note.editing = false;
- $(".note-box").resizable("enable");
- $(".note-box").draggable("enable");
- $(".note-box").removeClass("editing");
- });
$textarea.selectEnd();
- Note.editing = true;
- },
-
- parameterize_note: function($note_box, $note_body) {
- var $image = $("#image");
- var original_width = parseInt($image.data("original-width"));
- var ratio = parseInt($image.width()) / original_width;
-
- var hash = {
- note: {
- x: Math.round($note_box.position().left / ratio),
- y: Math.round($note_box.position().top / ratio),
- width: Math.round($note_box.width() / ratio),
- height: Math.round($note_box.height() / ratio),
- body: $note_body.data("original-body"),
- }
- }
-
- if ($note_box.data("id").match(/x/)) {
- hash.note.html_id = $note_box.data("id");
- hash.note.post_id = Utility.meta("post-id");
- }
-
- return hash;
- },
-
- error_handler: function(xhr, status, exception) {
- Utility.error("Error: " + (xhr.responseJSON.reason || xhr.responseJSON.reasons.join("; ")));
- },
-
- success_handler: function(data, status, xhr) {
- var $note_box = null;
-
- if (data.html_id) { // new note
- var $note_body = Note.Body.find(data.html_id);
- $note_box = Note.Box.find(data.html_id);
- $note_body.data("id", String(data.id)).attr("data-id", data.id);
- $note_box.data("id", String(data.id)).attr("data-id", data.id);
- $note_box.removeClass("new-note");
- $note_box.removeClass("unsaved");
- $note_box.removeClass("movable");
- } else {
- $note_box = Note.Box.find(data.id);
- $note_box.removeClass("unsaved");
- $note_box.removeClass("movable");
- }
- Note.move_id = null;
- },
-
- save: function() {
- var $this = $(this);
- var $textarea = $this.find("textarea");
- var id = $this.data("id");
- var $note_body = Note.Body.find(id);
- var $note_box = Note.Box.find(id);
- var text = $textarea.val();
- $note_body.data("original-body", text);
- Note.Body.set_text($note_body, $note_box, "Loading...");
- $.get("/note_previews.json", {body: text}).then(function(data) {
- Note.Body.set_text($note_body, $note_box, data.body);
- Note.Body.initialize($note_body);
- $note_body.show();
- });
- $this.dialog("close");
-
- if (id.match(/\d/)) {
- $.ajax("/notes/" + id + ".json", {
- type: "PUT",
- data: Note.Edit.parameterize_note($note_box, $note_body),
- error: Note.Edit.error_handler,
- success: Note.Edit.success_handler
- });
- } else {
- $.ajax("/notes.json", {
- type: "POST",
- data: Note.Edit.parameterize_note($note_box, $note_body),
- error: Note.Edit.error_handler,
- success: Note.Edit.success_handler
- });
- }
- },
-
- preview: function() {
- var $this = $(this);
- var $textarea = $this.find("textarea");
- var id = $this.data("id");
- var $note_body = Note.Body.find(id);
- var text = $textarea.val();
- var $note_box = Note.Box.find(id);
- $note_box.addClass("unsaved");
- Note.Body.set_text($note_body, $note_box, "Loading...");
- $.get("/note_previews.json", {body: text}).then(function(data) {
- Note.Body.set_text($note_body, $note_box, data.body);
- Note.Body.initialize($note_body);
- $note_body.show();
- });
- },
-
- cancel: function() {
- $(this).dialog("close");
- },
-
- destroy: function() {
- if (!confirm("Do you really want to delete this note?")) {
- return
- }
-
- var $this = $(this);
- var id = $this.data("id");
-
- if (id.match(/\d/)) {
- $.ajax("/notes/" + id + ".json", {
- type: "DELETE",
- success: function() {
- Note.Box.find(id).remove();
- Note.Body.find(id).remove();
- $this.dialog("close");
- }
- });
- }
- },
-
- history: function() {
- var $this = $(this);
- var id = $this.data("id");
- if (id.match(/\d/)) {
- window.location.href = "/note_versions?search[note_id]=" + id;
- }
- $(this).dialog("close");
}
- },
- TranslationMode: {
- active: false,
+ static async save($dialog, note) {
+ let $note_box = note.box.$note_box;
+ let text = $dialog.find("textarea").val();
- toggle: function(e) {
- if (Note.TranslationMode.active) {
- Note.TranslationMode.stop(e);
+ let params = {
+ x: Math.round(note.x * note.post_width),
+ y: Math.round(note.y * note.post_height),
+ width: Math.round(note.width * note.post_width),
+ height: Math.round(note.height * note.post_height),
+ body: text
+ };
+
+ note.original_body = text;
+ note.body.preview_text(text);
+
+ try {
+ if (note.is_new()) {
+ params.post_id = note.post_id;
+ let response = await $.ajax("/notes.json", { type: "POST", data: { note: params }});
+ note.id = response.id;
+ } else {
+ await $.ajax(`/notes/${note.id}.json`, { type: "PUT", data: { note: params }});
+ }
+
+ $dialog.dialog("close");
+ $note_box.removeClass("unsaved");
+ } catch (xhr) {
+ Utility.error("Error: " + (xhr.responseJSON.reason || xhr.responseJSON.reasons.join("; ")));
+ }
+ }
+
+ static async preview($dialog, note) {
+ let text = $dialog.find("textarea").val();
+
+ note.box.$note_box.addClass("unsaved");
+ note.body.preview_text(text);
+ }
+
+ static cancel($dialog, _note) {
+ $dialog.dialog("close");
+ }
+
+ static async destroy($dialog, note) {
+ if (!confirm("Do you really want to delete this note?")) {
+ return;
+ }
+
+ if (!note.is_new()) {
+ await $.ajax(`/notes/${note.id}.json`, { type: "DELETE" });
+ note.box.$note_box.remove();
+ note.body.$note_body.remove();
+ $dialog.dialog("close");
+ }
+ }
+
+ static history($dialog, note) {
+ if (!note.is_new()) {
+ window.location.href = `/note_versions?search[note_id]=${note.id}`;
+ }
+
+ $dialog.dialog("close");
+ }
+ }
+
+ static TranslationMode = class {
+ static toggle() {
+ if ($("body").hasClass("mode-translation")) {
+ Note.TranslationMode.stop();
} else {
- Note.TranslationMode.start(e);
+ Note.TranslationMode.start();
}
- },
+ }
- start: function(e) {
- e.preventDefault();
-
- if (CurrentUser.data("is-anonymous")) {
- Utility.notice("You must be logged in to edit notes");
- return;
- }
-
- if (Note.TranslationMode.active) {
- return;
- }
-
- $("#image").css("cursor", "crosshair");
- Note.TranslationMode.active = true;
+ static start() {
$(document.body).addClass("mode-translation");
$("#image").off("click.danbooru", Note.Box.toggle_all);
$("#image").on("mousedown.danbooru.note", Note.TranslationMode.Drag.start);
- $(document).on("mouseup.danbooru.note", Note.TranslationMode.Drag.stop);
- $("#mark-as-translated-section").show();
Utility.notice('Translation mode is on. Drag on the image to create notes. Turn translation mode off (shortcut is n).');
$("#notice a:contains(Turn translation mode off)").on("click.danbooru", Note.TranslationMode.stop);
- },
+ }
- stop: function(e) {
- e.preventDefault();
-
- Note.TranslationMode.active = false;
- $("#image").css("cursor", "auto");
+ static stop() {
+ $("#note-preview").hide();
$("#image").on("click.danbooru", Note.Box.toggle_all);
$("#image").off("mousedown.danbooru.note", Note.TranslationMode.Drag.start);
- $(document).off("mouseup.danbooru.note", Note.TranslationMode.Drag.stop);
+ $(document).off("mouseup.danbooru", Note.TranslationMode.Drag.stop);
+ $(document).off("mousemove.danbooru", Note.TranslationMode.Drag.drag);
$(document.body).removeClass("mode-translation");
$("#close-notice-link").click();
- $("#mark-as-translated-section").hide();
- },
+ }
- create_note: function(e, x, y, w, h) {
- if (w > 9 || h > 9) { /* minimum note size: 10px */
- if (w <= 9) {
- w = 10;
- } else if (h <= 9) {
- h = 10;
- }
- Note.create(x, y, w, h);
- }
+ static Drag = class {
+ static dragStartX = 0;
+ static dragStartY = 0;
- $(".note-container").removeClass("hide-notes");
- e.stopPropagation();
- e.preventDefault();
- },
-
- Drag: {
- dragging: false,
- dragStartX: 0,
- dragStartY: 0,
- dragDistanceX: 0,
- dragDistanceY: 0,
- x: 0,
- y: 0,
- w: 0,
- h: 0,
-
- start: function (e) {
+ static start(e) {
if (e.which !== 1) {
return;
}
+
e.preventDefault(); /* don't drag the image */
$(document).on("mousemove.danbooru", Note.TranslationMode.Drag.drag);
+ $(document).on("mouseup.danbooru", Note.TranslationMode.Drag.stop);
Note.TranslationMode.Drag.dragStartX = e.pageX;
Note.TranslationMode.Drag.dragStartY = e.pageY;
- },
+ }
- drag: function (e) {
- Note.TranslationMode.Drag.dragDistanceX = e.pageX - Note.TranslationMode.Drag.dragStartX;
- Note.TranslationMode.Drag.dragDistanceY = e.pageY - Note.TranslationMode.Drag.dragStartY;
+ static drag(e) {
var $image = $("#image");
var offset = $image.offset();
- var limitX1 = $image.width() - Note.TranslationMode.Drag.dragStartX + offset.left - 1;
- var limitX2 = offset.left - Note.TranslationMode.Drag.dragStartX;
- var limitY1 = $image.height() - Note.TranslationMode.Drag.dragStartY + offset.top - 1;
- var limitY2 = offset.top - Note.TranslationMode.Drag.dragStartY;
- if (Note.TranslationMode.Drag.dragDistanceX > limitX1) {
- Note.TranslationMode.Drag.dragDistanceX = limitX1;
- } else if (Note.TranslationMode.Drag.dragDistanceX < limitX2) {
- Note.TranslationMode.Drag.dragDistanceX = limitX2;
+ // (x0, y0) is the top left point of the drag box. (x1, y1) is the bottom right point.
+ let x0 = clamp(e.pageX, offset.left, Note.TranslationMode.Drag.dragStartX);
+ let y0 = clamp(e.pageY, offset.top, Note.TranslationMode.Drag.dragStartY);
+ let x1 = clamp(e.pageX, Note.TranslationMode.Drag.dragStartX, offset.left + $image.width());
+ let y1 = clamp(e.pageY, Note.TranslationMode.Drag.dragStartY, offset.top + $image.height());
+
+ // Convert from page-relative coordinates to image-relatives coordinates.
+ let x = x0 - offset.left;
+ let y = y0 - offset.top;
+ let w = x1 - x0;
+ let h = y1 - y0;
+
+ // Only show the new note box after we've dragged a minimum distance. This is to avoid
+ // accidentally creating tiny notes if we drag a small distance while trying to toggle notes.
+ if (w >= Note.MIN_NOTE_SIZE || h >= Note.MIN_NOTE_SIZE) {
+ $("#note-preview").show();
}
- if (Note.TranslationMode.Drag.dragDistanceY > limitY1) {
- Note.TranslationMode.Drag.dragDistanceY = limitY1;
- } else if (Note.TranslationMode.Drag.dragDistanceY < limitY2) {
- Note.TranslationMode.Drag.dragDistanceY = limitY2;
+ if ($("#note-preview").is(":visible")) {
+ $('#note-preview').css({ left: x, top: y, width: w, height: h });
}
+ }
- if (Math.abs(Note.TranslationMode.Drag.dragDistanceX) > 9 && Math.abs(Note.TranslationMode.Drag.dragDistanceY) > 9) {
- Note.TranslationMode.Drag.dragging = true; /* must drag at least 10pixels (minimum note size) in both dimensions. */
- }
- if (Note.TranslationMode.Drag.dragging) {
- if (Note.TranslationMode.Drag.dragDistanceX >= 0) {
- Note.TranslationMode.Drag.x = Note.TranslationMode.Drag.dragStartX - offset.left;
- Note.TranslationMode.Drag.w = Note.TranslationMode.Drag.dragDistanceX;
- } else {
- Note.TranslationMode.Drag.x = Note.TranslationMode.Drag.dragStartX - offset.left + Note.TranslationMode.Drag.dragDistanceX;
- Note.TranslationMode.Drag.w = -Note.TranslationMode.Drag.dragDistanceX;
- }
-
- if (Note.TranslationMode.Drag.dragDistanceY >= 0) {
- Note.TranslationMode.Drag.y = Note.TranslationMode.Drag.dragStartY - offset.top;
- Note.TranslationMode.Drag.h = Note.TranslationMode.Drag.dragDistanceY;
- } else {
- Note.TranslationMode.Drag.y = Note.TranslationMode.Drag.dragStartY - offset.top + Note.TranslationMode.Drag.dragDistanceY;
- Note.TranslationMode.Drag.h = -Note.TranslationMode.Drag.dragDistanceY;
- }
-
- $('#note-preview').css({
- display: 'block',
- left: (Note.TranslationMode.Drag.x + 1),
- top: (Note.TranslationMode.Drag.y + 1),
- width: (Note.TranslationMode.Drag.w - 3),
- height: (Note.TranslationMode.Drag.h - 3)
- });
- }
- },
-
- stop: function (e) {
- if (e.which !== 1) {
- return;
- }
- if (Note.TranslationMode.Drag.dragStartX === 0) {
- return; /* 'stop' is bound to window, don't create note if start wasn't triggered */
- }
+ static stop() {
$(document).off("mousemove.danbooru", Note.TranslationMode.Drag.drag);
+ $(document).off("mouseup.danbooru", Note.TranslationMode.Drag.stop);
- if (Note.TranslationMode.Drag.dragging) {
- $('#note-preview').css({ display: 'none' });
- Note.TranslationMode.create_note(e, Note.TranslationMode.Drag.x, Note.TranslationMode.Drag.y, Note.TranslationMode.Drag.w - 1, Note.TranslationMode.Drag.h - 1);
- Note.TranslationMode.Drag.dragging = false; /* border of the note is pixel-perfect on the preview border */
- } else { /* no dragging -> toggle display of notes */
+ if ($("#note-preview").is(":visible")) {
+ let $image = $("#image");
+
+ new Note({
+ x: $("#note-preview").position().left / $image.width(),
+ y: $("#note-preview").position().top / $image.height(),
+ w: $("#note-preview").width() / $image.width(),
+ h: $("#note-preview").height() / $image.height(),
+ });
+
+ $("#note-preview").hide();
+ $(".note-container").removeClass("hide-notes");
+ } else { /* If we didn't drag far enough, treat it as a click and toggle displaying notes. */
Note.Box.toggle_all();
}
-
- Note.TranslationMode.Drag.dragStartX = 0;
- Note.TranslationMode.Drag.dragStartY = 0;
}
}
- },
+ }
- id: "x",
- dragging: false,
- editing: false,
- move_id: null,
- drag_id: null,
- base_font_size: null,
- timeouts: [],
- pending: {},
+ constructor({ x, y, w, h, id = null, original_body = null, sanitized_body = null } = {}) {
+ this.$note_container = $(".note-container");
- add: function(container, id, x, y, w, h, original_body, sanitized_body) {
- var $note_box = Note.Box.create(id);
- var $note_body = Note.Body.create(id);
+ this.id = id;
+ this.post_id = this.$note_container.data("id");
+ this.embed = Utility.meta("post-has-embedded-notes") === "true";
+ this.original_body = original_body;
- $note_box.data('x', x);
- $note_box.data('y', y);
- $note_box.data('width', w);
- $note_box.data('height', h);
- container.appendChild($note_box[0]);
- container.appendChild($note_body[0]);
- $note_body.data("original-body", original_body);
- Note.Box.scale($note_box);
- if (Note.embed) {
- Note.Body.display_text($note_box.children("div.note-box-inner-border"), sanitized_body);
- Note.Body.display_text($note_body, "Click to edit");
- } else {
- Note.Body.display_text($note_body, sanitized_body);
- }
- },
+ this.box = new Note.Box(this);
+ this.body = new Note.Body(this);
- create: function(x, y, w, h) {
- var $note_box = Note.Box.create(Note.id);
- var $note_body = Note.Body.create(Note.id);
- $note_box.css({
- top: y,
- left: x,
- width: w,
- height: h
- });
- Note.Box.update_data_attributes($note_box);
- Note.Box.scale($note_box);
- $note_box.addClass("new-note");
- $note_box.addClass("unsaved");
- $note_body.html("Click to edit");
- $(".note-container").append($note_box);
- $(".note-container").append($note_body);
- Note.id += "x";
- },
+ this.box.place_note(x, y, w, h);
+ this.body.display_text(sanitized_body);
- normalize_sizes: function ($note_elements, parent_font_size) {
+ Note.notes.push(this);
+ }
+
+ is_new() {
+ return this.id === null;
+ }
+
+ // The coordinates of the top left corner of the note box, as floats in the
+ // range 0.0 to 1.0. Does not account for note rotation.
+ get x() {
+ return this.box.$note_box.position().left / this.image_width;
+ }
+
+ get y() {
+ return this.box.$note_box.position().top / this.image_height;
+ }
+
+ // The current width and height of the note box, as floats in the range 0.0 to 1.0.
+ get width() {
+ return this.box.$note_box.width() / this.image_width;
+ }
+
+ get height() {
+ return this.box.$note_box.height() / this.image_height;
+ }
+
+ // The width and height of the full-size original image in pixels.
+ get post_width() {
+ return parseInt(this.$note_container.attr("data-width"));
+ }
+
+ get post_height() {
+ return parseInt(this.$note_container.attr("data-height"));
+ }
+
+ // The current width and height of the image in pixels. Will be smaller than the post width
+ // if the sample image is being displayed, or if the image is resized to fit the screen.
+ get image_width() {
+ return parseInt(this.$note_container.width());
+ }
+
+ get image_height() {
+ return parseInt(this.$note_container.height());
+ }
+
+ // The initial font size of the note container. Embedded notes are scaled relative to this value.
+ get base_font_size() {
+ return parseFloat(this.$note_container.parent().css("font-size"));
+ }
+
+ normalize_sizes($note_elements, parent_font_size) {
if ($note_elements.length === 0) {
return;
}
- $note_elements.each(function(i, element) {
+
+ $note_elements.toArray().forEach((element) => {
const $element = $(element);
const computed_styles = window.getComputedStyle(element);
const font_size = parseFloat(computed_styles.fontSize);
- Note.NORMALIZE_ATTRIBUTES.forEach(function(attribute) {
+
+ Note.NORMALIZE_ATTRIBUTES.forEach((attribute) => {
const original_size = parseFloat(computed_styles[attribute]) || 0;
const relative_em = original_size / font_size;
$element.css(attribute, relative_em + "em");
});
+
const font_percentage = 100 * (font_size / parent_font_size);
$element.css("font-size", font_percentage + "%");
$element.attr("size", "");
- Note.normalize_sizes($element.children(), font_size);
+
+ this.normalize_sizes($element.children(), font_size);
});
- },
+ }
- clear_timeouts: function() {
- Note.timeouts.forEach(clearTimeout);
- Note.timeouts = [];
- },
+ static find(id) {
+ return Note.notes.find(note => note.id === id);
+ }
- load_all: function() {
- var fragment = document.createDocumentFragment();
- $.each($("#notes article"), function(i, article) {
+ static load_all() {
+ let $image = $(".image-container");
+
+ $("#notes article").toArray().forEach(article => {
var $article = $(article);
- Note.add(
- fragment,
- $article.data("id"),
- $article.data("x"),
- $article.data("y"),
- $article.data("width"),
- $article.data("height"),
- $article.data("body"),
- $article.html()
- );
- });
- const $note_container = $(".note-container");
- $note_container.append(fragment);
- if (Note.embed) {
- Note.base_font_size = parseFloat(window.getComputedStyle($note_container[0]).fontSize);
- $.each($(".note-box"), function(i, note_box) {
- const $note_box = $(note_box);
- Note.normalize_sizes($("div.note-box-inner-border", note_box).children(), Note.base_font_size);
- // Accounting for transformation values calculations which aren't correct immediately on page load
- setTimeout(()=>{Note.Box.copy_style_attributes($note_box);}, 100);
- });
- }
- Note.Box.scale_all();
- },
- initialize_all: function() {
+ new Note({
+ id: $article.data("id"),
+ x: $article.data("x") / $image.data("width"),
+ y: $article.data("y") / $image.data("height"),
+ w: $article.data("width") / $image.data("width"),
+ h: $article.data("height") / $image.data("height"),
+ original_body: $article.data("body"),
+ sanitized_body: $article.html()
+ });
+ });
+ }
+
+ static initialize_all() {
if ($("#c-posts #a-show #image").length === 0 || $("video#image").length) {
return;
}
- Note.embed = (Utility.meta("post-has-embedded-notes") === "true");
Note.load_all();
+ Note.Box.scale_all();
+
+ $(document).on("click.danbooru", "#translate", (e) => {
+ Note.TranslationMode.toggle();
+ e.preventDefault();
+ });
- this.initialize_shortcuts();
this.initialize_highlight();
$(document).on("hashchange.danbooru.note", this.initialize_highlight);
- Utility.keydown("up down left right", "nudge_note", Note.Box.key_nudge);
- Utility.keydown("shift+up shift+down shift+left shift+right", "resize_note", Note.Box.key_resize);
+
$(window).on("resize.danbooru.note_scale", Note.Box.scale_all);
- },
-
- initialize_shortcuts: function() {
- $("#translate").on("click.danbooru", Note.TranslationMode.toggle);
$("#image").on("click.danbooru", Note.Box.toggle_all);
- },
+ }
- initialize_highlight: function() {
+ static initialize_highlight() {
var matches = window.location.hash.match(/^#note-(\d+)$/);
if (matches) {
- var $note_box = Note.Box.find(matches[1]);
- Note.Box.show_highlighted($note_box);
+ let note_id = parseInt(matches[1]);
+ let note = Note.find(note_id);
+ note.box.show_highlighted();
}
- },
+ }
}
$(function() {
diff --git a/app/javascript/src/javascripts/utility.js b/app/javascript/src/javascripts/utility.js
index 4a335fd50..699278d7b 100644
--- a/app/javascript/src/javascripts/utility.js
+++ b/app/javascript/src/javascripts/utility.js
@@ -3,6 +3,10 @@ import Rails from '@rails/ujs';
let Utility = {};
+export function clamp(value, low, high) {
+ return Math.max(low, Math.min(value, high));
+}
+
Utility.delay = function(milliseconds) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}
diff --git a/app/javascript/src/styles/specific/notes.scss b/app/javascript/src/styles/specific/notes.scss
index ba02223ad..6fd6c9a59 100644
--- a/app/javascript/src/styles/specific/notes.scss
+++ b/app/javascript/src/styles/specific/notes.scss
@@ -7,7 +7,9 @@
}
div.note-body {
+ display: none;
position: absolute;
+ font-size: 14px;
border: var(--note-body-border);
background: var(--note-body-background);
color: var(--note-body-text-color);
@@ -81,7 +83,7 @@
justify-content: center;
align-items: center;
text-align: center;
- position: absolute;
+ position: absolute !important;
border: var(--note-box-border);
min-width: 5px;
min-height: 5px;
@@ -114,10 +116,6 @@
&.movable {
opacity: 1;
}
-
- div.ui-resizable-handle {
- display: block;
- }
}
&.editing,
@@ -134,19 +132,25 @@
border: var(--movable-note-box-border);
}
- div.ui-resizable-handle {
- display: none;
+ &:not(.hovering) div.ui-resizable-handle {
+ display: none !important;
}
}
&.note-box-highlighted {
outline: 2px solid var(--note-highlight-color);
}
+
+ div.ui-resizable-handle {
+ position: absolute;
+ }
}
}
+/* the box that appears when dragging to create a new note. */
div#note-preview {
position: absolute;
+ cursor: crosshair;
border: var(--note-preview-border);
opacity: 0.6;
display: none;
diff --git a/app/javascript/src/styles/specific/posts.scss b/app/javascript/src/styles/specific/posts.scss
index f6dfee59f..c657cc29d 100644
--- a/app/javascript/src/styles/specific/posts.scss
+++ b/app/javascript/src/styles/specific/posts.scss
@@ -436,6 +436,14 @@ body[data-post-current-image-size="original"] #image-resize-notice {
display: none;
}
+body.mode-translation .note-container {
+ cursor: crosshair;
+}
+
+body:not(.mode-translation) div#c-posts div#a-show #mark-as-translated-section {
+ display: none;
+}
+
div#c-post-versions, div#c-artist-versions {
div#a-index {
a {
diff --git a/app/views/posts/show.html.erb b/app/views/posts/show.html.erb
index 29d8467a9..b035b389c 100644
--- a/app/views/posts/show.html.erb
+++ b/app/views/posts/show.html.erb
@@ -61,7 +61,7 @@
<% end %>
<% end %>
-
+
<%= edit_form_for(@post, url: mark_as_translated_post_path(@post), method: :put) do |f| %>
<%= f.input :tags_query, as: :hidden, input_html: { id: nil, name: "tags_query", value: params[:q] } %>
<%= f.input :pool_id, as: :hidden, input_html: { id: nil, name: "pool_id", value: params[:pool_id] } %>