Rewrite the tag counter widget (the one above the tag edit box) to use
React. This is a trial run for using React elsewhere.
We actually use Preact instead of React because it's lighter weight.
We use Mobx for state management because it's cleaner than React's
setState or useState.
This incidentally fixes a couple bugs:
* The tag counter wasn't updated when deleting tags with backspace
* The tag counter wasn't updated when pasting in new tags.
* Show a banner if the user is restricted because they signed up from a
proxy or VPN.
* Add an option to resend the confirmation email if your account has an
unverified email address.
Bug: if you moused over another note while dragging a note, it would
trigger a note body popup. This would also happen when drawing out a new
note.
Also fix the drag box for new notes being drawn behind other notes.
Bug: loading and saving a note without moving it could change the note's
position. Moving a note with the keyboard could also cause unintended
changes to the note's size or position. This was because of floating
point errors when converting from percentage coordinates (floats) to pixel
coordinates (integers).
Fix: store note coordinates as pixel coordinates instead of as
percentage coordinates. Percentages are only used to position notes for
display.
Also fix it so you can resize rotated notes with the keyboard. This was
disabled before.
* Raise notes when hovering over them. This is so that when dragging
embedded notes, they're not hidden behind other notes. Also so that if
two notes are overlapping, you can hover over one to raise it over the
other.
* Replace .hovering class with :hover selector.
Bug: if you used they keyboard to move or resize a note, then the note
body would stay visible, which could get in the way when moving in the
down direction.
Bug: if you're editing a note and click preview, then you resize the
image or press V to toggle the image size, then the note body will stay
on the screen in the wrong position.
Bug: previewing a note would mark the note as unsaved even if the note
hadn't been changed.
Fix: mark the note as unsaved when the user types something into the
note edit box, not when the note is previewed.
Rewrite the notes Javascript from a procedural style to an
object-oriented style.
Before the notes Javascript had a lot of problems:
* There was hidden state everywhere, both locally and globally. We had
state in global variables, in <meta> tags, in DOM data-* attributes
(on multiple elements), and in jQuery .data() properties (which are
different from data-* attributes, because they aren't visible in the
DOM).
* Local state was hard to reason about. There was lots of direct DOM
manipulation in random places. Functions had to constantly pass around
note ids and look up elements in the DOM to get the state. State was
invisible because it was stored as jQuery .data() properties. It was
hard to follow where state was stored, how it was initialized, and how
it changed.
* Global state was also a mess. There were a lot of global flags and
variables only used in specific situations. Almost all of this state was
unnecessary. Global state also prevented us from doing things like
loading or unloading posts dynamically, or showing multiple posts with
notes on the same page.
* There was a lot of duplication of code, especially for placing notes,
and for loading or saving new notes versus saved notes.
Now the code is organized in an object-oriented fashion:
* The Note class represents a single note. A post has a list of notes,
and each note object has a Note.Box and a Note.Body. Together these
objects encapsulate the note's state.
* Notes have methods for doing things like placing note boxes, or showing
and hiding note bodies, or creating, saving, or deleting notes. This
makes the JS API cleaner.
* Global state is kept to a minimum.
This is one big patch because it was too hard to make these changes
incrementally. There are a couple minor bugfixes, but the actual
behavior of notes should remain unchanged.
Bugfixes:
* It was possible to enter translation mode, start dragging a new note,
then press N to leave translation mode while still dragging the note.
If you did this, then you would be stuck in translation mode and you
couldn't stop dragging the note.
* Placement of new notes is now pixel-perfect. Before when placing a
note, the note would shift by 1-2 pixels.
* Previewing an empty note didn't show the "Click to edit" message.
Other noteworthy changes:
* Most global state has been eliminated. There were a lot of flags and
variables stored as global variables on `Danbooru.Note`. Most of these
turned out to be either unnecessary or even unused.
* Notes now have an explicit minimum size of 10x10 pixels. Before this
limit was hardcoded and undocumented.
* A lot of the note placement and note creation code has been simplified.
* `Note.add()` and `Note.create()` have been refactored into `new Note()`.
Before `Note.add` was used to load an existing note, while `Note.create`
was used to create a new note. These did the same thing, but had
slightly different behavior.
* `Note.Box.scale()` and `Note.box.update_data_attributes` have been
refactored into `Note.Box.place_note()`. Contrary to their names,
these functions were actually both used to place notes.
Standardize font sizes and heading tags (<h1>-<h6>) to be more
consistent across the site.
Changes:
* Introduce font size CSS variables and start replacing hardcoded font
sizes with standard sizes.
* Change header tags to use only one <h1> per page. One <h1> per page is
recommended for SEO purposes. Usually this is for the page title, like
in forum threads or wiki pages.
* Standardize on <h2> for section headers in sidebars and <h3> for
smaller subsection headers. Don't use <h4>-<h6>.
* In DText, make h1-h4 headers all the same size. Standard wiki style is
to ignore h1-h3 and start at h4.
* In DText, make h4-h6 the same size as the h1-h3 tags outside of DText.
* In the tag list, change the <h1> and <h2> tag category headers to <h3>.
* Make usernames in comments and forum posts smaller. Also change the
<h4> tag for the commenter name to <div class="author-name">.
* Make the tag list, paginator, and nav menu smaller on mobile.
* Change h1#app-name-header to a#app-name-header.
When viewing a list of post #XXX links, like this:
* post #123
* post #456
* post #789
Then moving from bottom to top could cause multiple tooltips to appear
over one another. This was because tippy.js tries to keep tooltips
active while moving towards them, which meant it was possible to
activate a second tooltip while moving towards the first.
* Show completed uploads to other users.
* Don't show failed or incomplete uploads to other users.
* Don't show tags to other users.
* Delete completed uploads after 1 hour.
* Delete incomplete uploads after 1 day.
* Delete failed uploads after 3 days.
Change message to "Your account has been updated". It's possible for a
user to both gain and lose permissions at the same time, so just say
their account has been updated to make it easier.
Rework sitemaps to provide more coverage of the site. We want every
important page on the site - including every post, tag, and wiki page -
to be indexed by Google. We do this by generating sitemaps and sitemap
indexes that contain links to every important page on the site.
This was only used on the saved search index. It let you click on column
headers to sort the table by that column. This doesn't make sense now
that saved searches are paginated.
Bug: if you created an artist with the name of an existing general tag,
then the gentag would be changed to an artist tag, no matter how big the
gentag was.
Now we only allow creating artist entries for non-artist tags if the tag
is empty.
Ref: https://danbooru.donmai.us/forum_topics/17095
ArtStation is apparently returning images with smaller filesizes for
/4k/ images now. It doesn't look like we can get the old images, so just
update the tests.
Add rel=nofollow to various internal search links to prevent Google from
attempting to crawl things like `<tag> status:deleted` or `approver:<name>`
searches.
/packs was blocked by robots.txt, which prevented Googlebot from
fetching CSS when indexing pages, which made Google penalize pages for
being mobile unfriendly because it couldn't load the CSS and it thought
the layout was broken.
Bug: when a search timed out we got the generic failbooru page instead
of the search timeout error page.
Cause: when rendering the <link rel="next"> / <link rel="prev"> tags in
the header, we may need to evaluate the search to determine the next or
previous page, but if the searches times out then this fails, which
caused Rails to throw a ActionView::Template::Error because an exception
was thrown while rendering the template.
Likewise, rendering the attributes for the <body> tag could fail with an
ActionView::Template::Error because the call to `current_item.present?`
forced evaluation of the search.
Bug: The frontpage failed due to a SSL error. We couldn't fetch the
popular tag list from Reportbooru because Reportbooru's SSL certificate
had expired and HTTP.rb raised an SSLError exception that we didn't
catch.
Fix: Convert the SSLError to a 5xx HTTP error to prevent SSL exceptions
from leaking through HTTP.rb.
Remove sending dmail notifications to uploaders when an upload is
disapproved. These messages are usually confusing and frustrating to
uploaders. They don't know who is sending them and they usually feel
insulted when they get negative messages from anonymous users.
* Fix incorrect canonical tags. Before we were using
`<meta name="canonical" content="...">`. This is wrong, it should have been
`<link rel="canonical" href="...">`.
* Add a default canonical tag on all pages. Fixes Google treating the
same content on different subdomains (safebooru, shima, kagamihara, etc)
as duplicate content. Also fixes Google sometimes treating similar but
distinct content on the same domain as duplicate content.
Comparison:
* Codecov has a simpler integration and a better UI.
* Codeclimate tracks both linter warnings (Rubocop, ESLint) and code
coverage, but its UI for code coverage is worse than Codecov's.
* Codeclimate doesn't support Simplecov 0.18 because Codeclimate doesn't
support 0.18's new coverage format yet.
Fix the wiki excerpt not appearing when searching for a tag that doesn't
exist in the tag list. This could happen if someone created a wiki for a
tag that has never been used on a post.
* Only show the delete artist button on the artist edit page.
* Only show the delete pool button on the pool edit page.
* Only show the delete wiki button on the wiki edit page.
Makes it so that models that have maximum length validations will add
maxlength attributes to form fields. This includes flag reasons, appeal
reasons, and forum topic titles.
Partially fixes#4519 (Add "n/m characters remaining" character counter to the appeal reason).
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/maxlength
* Refactors DText form fields to use a custom SimpleForm input instead
of manually generated html. This fixes it so that DText fields use the
same markup as normal SimpleForm fields, which lets us apply browser
maxlength validations to DText input fields.
* Fixes autocomplete for @-mentions only working in comments and forum posts.
Now @-mention autocomplete works in all DText fields, including dmails.
Known bug: it applies in artist commentary fields when it shouldn't.
The image_url method makes a request to `https://seiga.nicovideo.jp/images/source/:image_id`
to see where this URL redirects to. Before we did a GET request, which caused it to download
the full image. This could fail with a timeout error if the download took too long. We also
cached the request, which caused the full image to be cached, even though we only need the
headers. Change it to a HEAD request so we don't have to download the entire image just to
check the URL.
* Factor out the Cloudflare Polish bypass code to a standalone feature.
* Add `http_downloader` method to the base source strategy. This is a
HTTP client that should be used for downloading images or making
requests to images. This client ensures that referrer spoofing and
Cloudflare bypassing are performed.
This fixes a bug with the upload page reporting the polished filesize
instead of the original filesize when uploading ArtStation images.