');
+ 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)) {
+ this.note.toggle_selected();
+ } 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() {
+ // Don't show note bodies if we mouseover another note while dragging or resizing.
+ if (!Note.dragging) {
+ this.note.body.show();
+ }
+ }
+
+ on_mouseleave() {
+ this.note.body.hide();
+ }
+
+ on_dragstart() {
+ this.$note_box.addClass("unsaved");
+ Note.Body.hide_all();
+ Note.dragging = true;
+ }
+
+ // 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 rescale them and convert back
+ // to percentage coordinates.
+ on_dragstop() {
+ let x = this.$note_box.position().left / this.note.scale_factor;
+ let y = this.$note_box.position().top / this.note.scale_factor;
+ let w = this.$note_box.width() / this.note.scale_factor;
+ let h = this.$note_box.height() / this.note.scale_factor;
+
+ this.place_note(x, y, w, h);
+ this.note.body.show();
+ Note.dragging = false;
+ }
+
+ // Place the note box. The input values are pixel coordinates relative to the full image.
+ 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.scale_factor;
+ y = position.norm_top / this.note.scale_factor;
+ }
+
+ this.note.w = Math.round(clamp(w, Note.MIN_NOTE_SIZE, this.note.post_width));
+ this.note.h = Math.round(clamp(h, Note.MIN_NOTE_SIZE, this.note.post_height));
+ this.note.x = Math.round(clamp(x, 0, this.note.post_width - this.note.w));
+ this.note.y = Math.round(clamp(y, 0, this.note.post_height - this.note.h));
+
+ this.$note_box.css({
+ top: (100 * this.note.y / this.note.post_height) + '%',
+ left: (100 * this.note.x / this.note.post_width) + '%',
+ width: (100 * this.note.w / this.note.post_width) + '%',
+ height: (100 * this.note.h / this.note.post_height) + '%',
+ });
+ }
+
+ 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,210 +158,103 @@ 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) {
switch (event.originalEvent.key) {
case "ArrowUp":
- current_top--;
+ this.note.y--;
break;
case "ArrowDown":
- current_top++;
+ this.note.y++;
break;
case "ArrowLeft":
- current_left--;
+ this.note.x--;
break;
case "ArrowRight":
- current_left++;
+ this.note.x++;
break;
default:
// do nothing
}
- let position = Note.Box.get_min_max_position($note_box, 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));
- let current_height = $note_box.height();
- let current_width = $note_box.width();
+ this.place_note(this.note.x, this.note.y, this.note.w, this.note.h);
+ Note.Body.hide_all();
+ this.$note_box.addClass("unsaved");
+ event.preventDefault();
+ }
+
+ key_resize(event) {
switch (event.originalEvent.key) {
case "ArrowUp":
- current_height--;
+ this.note.h--;
break;
case "ArrowDown":
- current_height++;
+ this.note.h++;
break;
case "ArrowLeft":
- current_width--;
+ this.note.w--;
break;
case "ArrowRight":
- current_width++;
+ this.note.w++;
break;
default:
// do nothing
}
- const position = Note.Box.get_min_max_position($note_box, 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) {
+ this.place_note(this.note.x, this.note.y, this.note.w, this.note.h);
+ Note.Body.hide_all();
+ this.$note_box.addClass("unsaved");
+ event.preventDefault();
+ }
+
+ 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 +262,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 +289,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 +298,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 +312,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 +328,64 @@ 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 $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() {
+ Note.Body.hide_all();
+
+ let large_width = parseFloat($container.data("large-width"));
+ let ratio = $container.width() / large_width;
+ let font_percentage = ratio * 100;
+
+ $container.css('font-size', font_percentage + '%');
+ }
+
+ static toggle_all() {
+ Note.Body.hide_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 +396,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,92 +480,93 @@ 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.val(note.original_body);
$textarea.css({
- width: "97%",
height: "85%",
resize: "none",
});
- if (!$note_body.hasClass("new-note")) {
- $textarea.val($note_body.data("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 +578,343 @@ let Note = {
classes: {
"ui-dialog": "note-edit-dialog",
},
+ open: () => {
+ Utility.keydown("ctrl+return", "save_note", () => this.save($dialog, note), ".note-edit-dialog textarea");
+ $(".note-edit-dialog textarea").on("input.danbooru", (e) => this.on_input(note));
+ $(".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 on_input(note) {
+ note.box.$note_box.addClass("unsaved");
+ }
- toggle: function(e) {
- if (Note.TranslationMode.active) {
- Note.TranslationMode.stop(e);
+ static async save($dialog, note) {
+ let $note_box = note.box.$note_box;
+ let text = $dialog.find("textarea").val();
+
+ let params = {
+ x: note.x,
+ y: note.y,
+ width: note.w,
+ height: note.h,
+ 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.body.preview_text(text);
+ }
+
+ static cancel($dialog, _note) {
+ $dialog.dialog("close");
+ }
+
+ static async destroy($dialog, note) {
+ if (!note.is_new() && !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();
+ Note.notes.delete(note);
+
+ $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;
- },
+ Note.dragging = true;
+ }
- 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() {
+ Note.dragging = false;
$(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 scale_factor = $(".note-container").width() / parseInt($(".note-container").attr("data-width"));
+
+ new Note({
+ x: $("#note-preview").position().left / scale_factor,
+ y: $("#note-preview").position().top / scale_factor,
+ w: $("#note-preview").width() / scale_factor,
+ h: $("#note-preview").height() / scale_factor,
+ });
+
+ $("#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;
+ this.x = x;
+ this.y = y;
+ this.w = w;
+ this.h = h;
- $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.add(this);
+ }
+
+ is_new() {
+ return this.id === null;
+ }
+
+ // The ratio of the current image size to the full image size.
+ get scale_factor() {
+ return this.$note_container.width() / this.post_width;
+ }
+
+ // 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"));
+ }
+
+ is_selected() {
+ return this.box.$note_box.hasClass("movable");
+ }
+
+ toggle_selected() {
+ return this.is_selected() ? this.unselect() : this.select();
+ }
+
+ select() {
+ Note.unselect_all();
+ this.box.$note_box.addClass("movable");
+ Utility.keydown("up down left right", "nudge_note", this.box.key_nudge.bind(this.box));
+ Utility.keydown("shift+up shift+down shift+left shift+right", "resize_note", this.box.key_resize.bind(this.box));
+ }
+
+ unselect() {
+ this.box.$note_box.removeClass("movable");
+ $(document).off("keydown.nudge_note");
+ $(document).off("keydown.resize_note");
+ }
+
+ 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 Array.from(Note.notes).find(note => note.id === id);
+ }
- load_all: function() {
- var fragment = document.createDocumentFragment();
- $.each($("#notes article"), function(i, article) {
+ static load_all() {
+ $("#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"),
+ y: $article.data("y"),
+ w: $article.data("width"),
+ h: $article.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();
}
- },
+ }
+
+ static unselect_all() {
+ Note.notes.forEach(note => note.unselect());
+ }
}
$(function() {
diff --git a/app/javascript/src/javascripts/post_tooltips.js b/app/javascript/src/javascripts/post_tooltips.js
index 8daf42234..b4563756c 100644
--- a/app/javascript/src/javascripts/post_tooltips.js
+++ b/app/javascript/src/javascripts/post_tooltips.js
@@ -17,7 +17,7 @@ PostTooltip.initialize = function () {
delegate("body", {
allowHTML: true,
- appendTo: document.body,
+ appendTo: document.querySelector("#post-tooltips"),
delay: [PostTooltip.SHOW_DELAY, PostTooltip.HIDE_DELAY],
duration: PostTooltip.DURATION,
interactive: true,
diff --git a/app/javascript/src/javascripts/posts.js.erb b/app/javascript/src/javascripts/posts.js.erb
index 9eef63e88..db4ac4be1 100644
--- a/app/javascript/src/javascripts/posts.js.erb
+++ b/app/javascript/src/javascripts/posts.js.erb
@@ -14,6 +14,7 @@ Post.SWIPE_VELOCITY = 0.6;
Post.MAX_RECOMMENDATIONS = 45; // 3 rows of 9 posts at 1920x1080.
Post.LOW_TAG_COUNT = 10;
Post.HIGH_TAG_COUNT = 20;
+Post.EDIT_DIALOG_WIDTH = 720;
Post.initialize_all = function() {
@@ -42,8 +43,6 @@ Post.initialize_all = function() {
}
var $fields_multiple = $('[data-autocomplete="tag-edit"]');
- $fields_multiple.on("keypress.danbooru", Post.update_tag_count);
- $fields_multiple.on("click", Post.update_tag_count);
$(window).on('danbooru:initialize_saved_seraches', () => {
Post.initialize_saved_searches();
@@ -105,14 +104,13 @@ Post.open_edit_dialog = function() {
$("#post-edit-link").parent("li").addClass("active");
var $tag_string = $("#post_tag_string,#upload_tag_string");
- $("div.input").has($tag_string).prevAll().hide();
$("#open-edit-dialog").hide();
var dialog = $("").attr("id", "edit-dialog");
$("#form").appendTo(dialog);
dialog.dialog({
title: "Edit tags",
- width: $(window).width() * 0.6,
+ width: Post.EDIT_DIALOG_WIDTH,
position: {
my: "right",
at: "right-20",
@@ -307,10 +305,11 @@ Post.view_original = function(e = null) {
}
var $image = $("#image");
+ var $post = $(".image-container");
$image.attr("src", $(".image-view-original-link").attr("href"));
$image.css("filter", "blur(8px)");
- $image.width($image.data("original-width"));
- $image.height($image.data("original-height"));
+ $image.width($post.data("width"));
+ $image.height($post.data("height"));
$image.on("load.danbooru", function() {
$image.css("animation", "sharpen 0.5s forwards");
});
@@ -326,10 +325,11 @@ Post.view_large = function(e = null) {
}
var $image = $("#image");
+ var $post = $(".image-container");
$image.attr("src", $(".image-view-large-link").attr("href"));
$image.css("filter", "blur(8px)");
- $image.width($image.data("large-width"));
- $image.height($image.data("large-height"));
+ $image.width($post.data("large-width"));
+ $image.height($post.data("large-height"));
$image.on("load.danbooru", function() {
$image.css("animation", "sharpen 0.5s forwards");
});
@@ -400,7 +400,6 @@ Post.initialize_post_sections = function() {
$("#post_tag_string").focus().selectEnd().height($("#post_tag_string")[0].scrollHeight);
$("#recommended").hide();
$(document).trigger("danbooru:open-post-edit-tab");
- Post.update_tag_count({target: $("#post_tag_string")});
} else if (e.target.hash === "#recommended") {
$("#comments").hide();
$("#edit").hide();
@@ -511,32 +510,6 @@ Post.initialize_recommended = function() {
});
};
-Post.update_tag_count = function(event) {
- let string = "0 tags";
- let count = 0;
-
- if (event) {
- let tags = Utility.regexp_split($(event.target).val());
- if (tags.length) {
- count = tags.length;
- string = (count === 1) ? (count + " tag") : (count + " tags")
- }
- }
-
- $("#tags-container .count").html(string);
- let klass = "";
-
- if (count < Post.LOW_TAG_COUNT) {
- klass = "frown";
- } else if (count >= Post.LOW_TAG_COUNT && count < Post.HIGH_TAG_COUNT) {
- klass = "meh";
- } else {
- klass = "smile";
- }
-
- $("#tags-container .options #face").removeClass().addClass(`far fa-${klass}`);
-}
-
$(document).ready(function() {
Post.initialize_all();
});
diff --git a/app/javascript/src/javascripts/related_tag.js b/app/javascript/src/javascripts/related_tag.js
index 3f09339ba..13dc61927 100644
--- a/app/javascript/src/javascripts/related_tag.js
+++ b/app/javascript/src/javascripts/related_tag.js
@@ -1,6 +1,5 @@
import Uploads from './uploads.js.erb';
import Utility from './utility';
-import Post from './posts.js.erb';
let RelatedTag = {};
@@ -121,7 +120,8 @@ RelatedTag.toggle_tag = function(e) {
setTimeout(function () { $field.prop('selectionStart', $field.val().length);}, 100);
e.preventDefault();
- Post.update_tag_count({ target: $field });
+ // Artificially trigger input event so the tag counter updates.
+ $field.trigger("input");
}
RelatedTag.show = function(e) {
diff --git a/app/javascript/src/javascripts/tag_counter.js b/app/javascript/src/javascripts/tag_counter.js
new file mode 100644
index 000000000..37ff8f46d
--- /dev/null
+++ b/app/javascript/src/javascripts/tag_counter.js
@@ -0,0 +1,49 @@
+import { h, Component, render } from "preact";
+import { observable, computed, action } from "mobx";
+import { observer } from "mobx-react";
+
+import Utility from "./utility";
+
+export default @observer class TagCounter extends Component {
+ static lowCount = 10;
+ static highCount = 20;
+
+ @observable tagCount = 0;
+
+ componentDidMount() {
+ $(this.props.tags).on("input", this.updateCount);
+ this.updateCount();
+ }
+
+ render() {
+ return (
+
+ {this.tagCount} / {TagCounter.highCount} tags
+
+
+ );
+ }
+
+ @action.bound updateCount() {
+ this.tagCount = Utility.regexp_split($(this.props.tags).val()).length;
+ }
+
+ @computed get iconName() {
+ if (this.tagCount < TagCounter.lowCount) {
+ return "blobglare";
+ } else if (this.tagCount >= TagCounter.lowCount && this.tagCount < TagCounter.highCount) {
+ return "blobthinkingglare";
+ } else {
+ return "blobaww";
+ }
+ }
+
+ static initialize() {
+ $("[data-tag-counter]").toArray().forEach(element => {
+ let target = $($(element).attr("data-for")).get(0);
+ render(h(TagCounter, { tags: target }), element);
+ });
+ }
+}
+
+$(TagCounter.initialize);
diff --git a/app/javascript/src/javascripts/uploads.js.erb b/app/javascript/src/javascripts/uploads.js.erb
index 800090537..a5ce47c5b 100644
--- a/app/javascript/src/javascripts/uploads.js.erb
+++ b/app/javascript/src/javascripts/uploads.js.erb
@@ -143,10 +143,13 @@ Upload.toggle_size = function(e) {
Upload.update_scale = function() {
let $image = $("#image");
- let natural_width = $image.get(0).naturalWidth;
- let natural_height = $image.get(0).naturalHeight;
- let scale_percentage = Math.round(100 * $image.width() / natural_width);
- $("#upload-image-metadata-resolution").html(`(${natural_width}x${natural_height}, resized to ${scale_percentage}%)`);
+
+ if ($image.length) {
+ let natural_width = $image.get(0).naturalWidth;
+ let natural_height = $image.get(0).naturalHeight;
+ let scale_percentage = Math.round(100 * $image.width() / natural_width);
+ $("#upload-image-metadata-resolution").html(`(${natural_width}x${natural_height}, resized to ${scale_percentage}%)`);
+ }
}
Upload.fetch_data_manual = function(e) {
diff --git a/app/javascript/src/javascripts/user_tooltips.js b/app/javascript/src/javascripts/user_tooltips.js
index cc0a9f3b9..eff985a8c 100644
--- a/app/javascript/src/javascripts/user_tooltips.js
+++ b/app/javascript/src/javascripts/user_tooltips.js
@@ -11,9 +11,9 @@ UserTooltip.DURATION = 250;
UserTooltip.MAX_WIDTH = 600;
UserTooltip.initialize = function () {
- delegate("body", {
+ delegate("#page", {
allowHTML: true,
- appendTo: document.body,
+ appendTo: document.querySelector("#user-tooltips"),
delay: [UserTooltip.SHOW_DELAY, UserTooltip.HIDE_DELAY],
duration: UserTooltip.DURATION,
interactive: true,
@@ -26,7 +26,7 @@ UserTooltip.initialize = function () {
onHide: UserTooltip.on_hide,
});
- delegate("body", {
+ delegate("#user-tooltips", {
allowHTML: true,
interactive: true,
theme: "common-tooltip",
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/base/000_vars.scss b/app/javascript/src/styles/base/000_vars.scss
index af4897f49..26b84d025 100644
--- a/app/javascript/src/styles/base/000_vars.scss
+++ b/app/javascript/src/styles/base/000_vars.scss
@@ -1,21 +1,20 @@
-$h1_size: 2em;
-$h2_size: 1.5em;
-$h3_size: 1.16667em;
-$h4_size: 1em;
-$dtext_h1_size: 2em;
-$dtext_h2_size: 1.8em;
-$dtext_h3_size: 1.6em;
-$dtext_h4_size: 1.4em;
-$dtext_h5_size: 1.2em;
-$dtext_h6_size: 1em;
+:root {
+ --text-xs: 0.8em;
+ --text-sm: 0.9em;
+ --text-md: 1em;
+ --text-lg: 1.16667em;
+ --text-xl: 1.5em;
+ --text-xxl: 2em;
+ --header-font: Tahoma, Verdana, Helvetica, sans-serif;
+ --body-font: Verdana, Helvetica, sans-serif;
+ --monospace-font: 1.2em monospace;
+}
+
$h1_padding: 0.8em 0 0.25em 0;
$h2_padding: 0.8em 0 0.25em 0;
$h3_padding: 0.8em 0 0.25em 0;
$h4_padding: 0.8em 0 0.25em 0;
-/* stylelint-disable-next-line value-keyword-case */
-$base_font_family: Verdana, Helvetica, sans-serif;
-
@mixin animated-icon {
content: "►";
position: absolute;
diff --git a/app/javascript/src/styles/base/020_base.scss b/app/javascript/src/styles/base/020_base.scss
index 352f46349..00180c2c6 100644
--- a/app/javascript/src/styles/base/020_base.scss
+++ b/app/javascript/src/styles/base/020_base.scss
@@ -1,9 +1,7 @@
-@import "../base/000_vars.scss";
-
body {
color: var(--text-color);
background-color: var(--body-background-color);
- font-family: $base_font_family;
+ font-family: var(--body-font);
font-size: 87.5%;
line-height: 1.25em;
}
@@ -12,11 +10,6 @@ abbr[title=required] {
display: none;
}
-code {
- font-family: monospace;
- font-size: 1.2em;
-}
-
dd {
margin-bottom: 1em;
}
@@ -25,22 +18,23 @@ dt {
font-weight: bold;
}
-h1, h2, h3, h4, h5, h6 {
- font-family: Tahoma, Verdana, Helvetica, sans-serif;
+h1, h2, h3, h4, h5, h6, .heading {
+ font-family: var(--header-font);
+ font-weight: bold;
line-height: 1.5em;
color: var(--header-color);
}
h1 {
- font-size: $h1_size;
+ font-size: var(--text-xxl);
}
h2 {
- font-size: $h2_size;
+ font-size: var(--text-lg);
}
h3, h4, h5, h6 {
- font-size: $h3_size;
+ font-size: var(--text-md);
}
fieldset {
@@ -62,6 +56,11 @@ input, select, textarea {
border: var(--form-input-border);
color: var(--form-input-text-color);
padding-left: 0.25em;
+ font: var(--body-font);
+}
+
+textarea {
+ font-size: var(--text-sm);
}
input[type="button"], input[type="submit"], button {
diff --git a/app/javascript/src/styles/base/040_colors.css b/app/javascript/src/styles/base/040_colors.css
index 211b835fc..28eef86ec 100644
--- a/app/javascript/src/styles/base/040_colors.css
+++ b/app/javascript/src/styles/base/040_colors.css
@@ -104,10 +104,8 @@
--post-parent-notice-background: var(--success-background-color);
--post-child-notice-background: var(--warning-background-color);
--post-pending-notice-background: #D8D8FC;
- --post-flagged-notice-background: var(--error-background-color);
--post-banned-notice-background: var(--error-background-color);
--post-deleted-notice-background: var(--error-background-color);
- --post-appealed-notice-background: #D8F2FC;
--post-resized-notice-background: #EED8FC;
--post-search-notice-background: #EEE;
@@ -145,10 +143,6 @@
--tag-count-color: var(--muted-text-color);
--low-post-count-color: red;
- --tag-count-indicator-frown-color: red;
- --tag-count-indicator-meh-color: darkkhaki;
- --tag-count-indicator-smile-color: green;
-
--remove-favorite-button: deeppink;
--ugoira-seek-slider-background: #EEE;
@@ -387,10 +381,8 @@ body[data-current-user-theme="dark"] {
--post-parent-notice-background: var(--green-0);
--post-resized-notice-background: var(--purple-0);
--post-pending-notice-background: var(--indigo-0);
- --post-flagged-notice-background: var(--red-0);
--post-deleted-notice-background: var(--red-0);
--post-banned-notice-background: var(--red-0);
- --post-appealed-notice-background: var(--blue-0);
--post-tooltip-background-color: var(--grey-3);
--post-tooltip-border-color: var(--grey-4);
@@ -417,10 +409,6 @@ body[data-current-user-theme="dark"] {
--target-background: var(--blue-0);
- --tag-count-indicator-frown-color: var(--red-1);
- --tag-count-indicator-meh-color: var(--yellow-1);
- --tag-count-indicator-smile-color: var(--green-1);
-
--uploads-dropzone-background: var(--grey-3);
--uploads-dropzone-progress-bar-foreground-color: var(--link-color);
--uploads-dropzone-progress-bar-background-color: var(--link-hover-color);
diff --git a/app/javascript/src/styles/common/dtext.scss b/app/javascript/src/styles/common/dtext.scss
index 6a9066af4..40627770d 100644
--- a/app/javascript/src/styles/common/dtext.scss
+++ b/app/javascript/src/styles/common/dtext.scss
@@ -9,32 +9,32 @@ div.prose {
}
h1 {
- font-size: $dtext_h1_size;
+ font-size: var(--text-xl);
padding: $h1_padding;
}
h2 {
- font-size: $dtext_h2_size;
+ font-size: var(--text-xl);
padding: $h2_padding;
}
h3 {
- font-size: $dtext_h3_size;
+ font-size: var(--text-xl);
padding: $h3_padding;
}
h4 {
- font-size: $dtext_h4_size;
+ font-size: var(--text-xl);
padding: $h4_padding;
}
h5 {
- font-size: $dtext_h5_size;
+ font-size: var(--text-lg);
padding: $h4_padding;
}
h6 {
- font-size: $dtext_h6_size;
+ font-size: var(--text-md);
padding: $h4_padding;
}
@@ -57,12 +57,14 @@ div.prose {
list-style-type: disc;
}
+ code, pre {
+ font: var(--monospace-font);
+ background: var(--dtext-code-background);
+ }
+
pre {
- font-family: monospace;
- font-size: 1.2em;
margin: 0.5em 0;
padding: 0.5em 1em;
- background: var(--dtext-code-background);
white-space: pre-wrap;
}
@@ -73,11 +75,6 @@ div.prose {
background: var(--dtext-blockquote-background);
}
- code {
- font-family: monospace;
- background: var(--dtext-code-background);
- }
-
.tn {
font-size: 0.8em;
color: var(--muted-text-color);
diff --git a/app/javascript/src/styles/common/jquery_ui_custom.scss b/app/javascript/src/styles/common/jquery_ui_custom.scss
index 5d28e30b2..85137ce8c 100644
--- a/app/javascript/src/styles/common/jquery_ui_custom.scss
+++ b/app/javascript/src/styles/common/jquery_ui_custom.scss
@@ -1,10 +1,8 @@
-@import "../base/000_vars.scss";
-
.ui-widget {
- font-family: $base_font_family;
+ font-family: var(--body-font);
input, select, textarea, button {
- font-family: $base_font_family;
+ font-family: var(--body-font);
}
}
diff --git a/app/javascript/src/styles/common/main_layout.scss b/app/javascript/src/styles/common/main_layout.scss
index 1af5253b4..31311a6a2 100644
--- a/app/javascript/src/styles/common/main_layout.scss
+++ b/app/javascript/src/styles/common/main_layout.scss
@@ -6,10 +6,6 @@ div#page {
padding: 0 10px;
aside#sidebar {
- h1 {
- font-size: $h3_size;
- }
-
#options-box i.fa-bookmark {
margin-right: 0.25em;
}
diff --git a/app/javascript/src/styles/common/messages.scss b/app/javascript/src/styles/common/messages.scss
index 4d70c0103..b38857027 100644
--- a/app/javascript/src/styles/common/messages.scss
+++ b/app/javascript/src/styles/common/messages.scss
@@ -15,6 +15,10 @@ div.list-of-messages {
width: 12em;
margin-right: 1em;
+ div.author-name {
+ font-weight: bold;
+ }
+
a.message-timestamp {
font-style: italic;
font-size: 0.90em;
@@ -42,7 +46,7 @@ div.list-of-messages {
margin: 0 0 1em;
width: auto;
- h4 {
+ div.author-name {
display: inline;
margin-right: 0.5em;
}
diff --git a/app/javascript/src/styles/common/page_header.scss b/app/javascript/src/styles/common/page_header.scss
index ea89e5394..11301b97e 100644
--- a/app/javascript/src/styles/common/page_header.scss
+++ b/app/javascript/src/styles/common/page_header.scss
@@ -3,8 +3,8 @@
}
header#top {
- h1#app-name-header {
- font-size: 2em;
+ #app-name-header {
+ font-size: var(--text-xxl);
margin: 0 30px;
}
diff --git a/app/javascript/src/styles/common/simple_form.scss b/app/javascript/src/styles/common/simple_form.scss
index 2b1706df4..d0304dc44 100644
--- a/app/javascript/src/styles/common/simple_form.scss
+++ b/app/javascript/src/styles/common/simple_form.scss
@@ -48,7 +48,6 @@ form.simple_form {
textarea {
width: 70%;
- font-size: 1.2em;
}
label {
@@ -107,10 +106,31 @@ form.one-line-form {
}
div.ui-dialog {
- div.input {
- input[type="text"] {
- width: 100%;
- max-width: 100%;
+ textarea, input[type="text"] {
+ width: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+ }
+
+ form.simple_form {
+ margin-bottom: 0;
+
+ div.input {
+ margin-bottom: 0.5em;
+ }
+
+ div.input.hidden {
+ display: none;
+ }
+ }
+
+ /* the submit and close buttons */
+ .ui-dialog-buttonpane {
+ margin-top: 0;
+ padding: 1em 1em 1em 0;
+
+ .ui-button {
+ margin: 0 0.25em;
}
}
}
diff --git a/app/javascript/src/styles/specific/error.scss b/app/javascript/src/styles/specific/error.scss
index cbd2288fc..468a2c41e 100644
--- a/app/javascript/src/styles/specific/error.scss
+++ b/app/javascript/src/styles/specific/error.scss
@@ -1,6 +1,5 @@
ul.backtrace {
- font-family: monospace;
- font-size: 1.2em;
+ font: var(--monospace-font);
background: var(--dtext-code-background);
padding: 1em;
margin-bottom: 1em;
diff --git a/app/javascript/src/styles/specific/notes.scss b/app/javascript/src/styles/specific/notes.scss
index ba02223ad..96f32264c 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;
@@ -93,6 +95,11 @@
opacity: 0.5;
z-index: 100;
+ /* Raise notes on hover so overlapping embedded notes are readable. */
+ &:hover {
+ z-index: 200;
+ }
+
&.unsaved {
border: var(--unsaved-note-box-border);
}
@@ -106,7 +113,7 @@
border: 1px solid transparent;
opacity: 1;
- &.hovering {
+ &:hover {
border: var(--note-box-border);
box-shadow: var(--note-box-shadow);
@@ -114,10 +121,6 @@
&.movable {
opacity: 1;
}
-
- div.ui-resizable-handle {
- display: block;
- }
}
&.editing,
@@ -134,24 +137,30 @@
border: var(--movable-note-box-border);
}
- div.ui-resizable-handle {
- display: none;
+ &:not(:hover) 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;
background: var(--note-preview-background);
- z-index: 100;
+ z-index: 250;
}
div.note-edit-dialog {
diff --git a/app/javascript/src/styles/specific/pools.scss b/app/javascript/src/styles/specific/pools.scss
index 9ef7f703f..93d90cc3f 100644
--- a/app/javascript/src/styles/specific/pools.scss
+++ b/app/javascript/src/styles/specific/pools.scss
@@ -27,17 +27,9 @@ div#add-to-pool-dialog {
margin-left: 1em;
cursor: pointer;
}
-
- h1 {
- font-size: $h3_size;
- }
}
div#c-pools {
- h1 {
- font-size: $h2_size;
- }
-
textarea {
height: 10em;
}
@@ -50,10 +42,6 @@ div#c-pools {
}
div#c-pool-orders, div#c-favorite-group-orders {
- h1 {
- font-size: $h2_size;
- }
-
div#a-edit {
ul.ui-sortable {
list-style-type: none;
diff --git a/app/javascript/src/styles/specific/posts.scss b/app/javascript/src/styles/specific/posts.scss
index 03a8eb93c..1eca2209a 100644
--- a/app/javascript/src/styles/specific/posts.scss
+++ b/app/javascript/src/styles/specific/posts.scss
@@ -80,8 +80,13 @@ table article.post-preview {
margin-top: 1em;
}
-#edit-dialog textarea {
- margin-bottom: 0.25em;
+#edit-dialog {
+ /* Hide everything but the rating and tags fields. */
+ .post_has_embedded_notes_fieldset, .post_lock_fieldset, .post_parent_id,
+ .post_source, #filedropzone, .upload_as_pending, .upload_source_container,
+ .upload_parent_id, .upload_artist_commentary_container, .upload_commentary_translation_container {
+ display: none;
+ }
}
.post-preview {
@@ -258,26 +263,15 @@ div#c-posts {
margin-bottom: 0;
}
- .resolved {
- margin-left: 0.5em;
- font-weight: bold;
- }
-
&.post-notice-parent { background: var(--post-parent-notice-background); }
&.post-notice-child { background: var(--post-child-notice-background); }
&.post-notice-pending { background: var(--post-pending-notice-background); }
- &.post-notice-flagged { background: var(--post-flagged-notice-background); }
&.post-notice-banned { background: var(--post-banned-notice-background); }
&.post-notice-deleted { background: var(--post-deleted-notice-background); }
- &.post-notice-appealed { background: var(--post-appealed-notice-background); }
&.post-notice-resized { background: var(--post-resized-notice-background); }
&.post-notice-search { background: var(--post-search-notice-background); }
}
- aside#sidebar #tag-list h2 {
- font-size: $h4_size;
- }
-
aside#sidebar > section > ul {
margin-bottom: 1em;
@@ -308,7 +302,7 @@ div#c-posts {
div#a-index {
menu#post-sections {
margin-bottom: 0.5em;
- font-size: $h3_size;
+ font-size: var(--text-lg);
li {
padding: 0 1em 0.5em 0;
@@ -331,7 +325,7 @@ div#c-posts {
menu#post-sections {
margin: 0;
- font-size: $h3_size;
+ font-size: var(--text-lg);
li {
padding: 0 1em 0 0;
@@ -434,12 +428,27 @@ div#c-posts {
}
}
-body[data-post-current-image-size="large"] .image-view-large-link,
-body[data-post-current-image-size="original"] .image-view-original-link,
+body[data-post-current-image-size="large"] #post-options .image-view-large-link,
+body[data-post-current-image-size="original"] #post-options .image-view-original-link,
body[data-post-current-image-size="original"] #image-resize-notice {
display: none;
}
+/* Always show the "Resized to X% of original" notice on mobile when it exists. */
+#image-resize-notice {
+ @media screen and (max-width: 660px) {
+ display: block !important;
+ }
+}
+
+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 {
@@ -474,6 +483,33 @@ div#c-posts, div#c-uploads {
}
}
+/* Container for the tag edit