If user types "tag1 tag2" then adds a comma between,
it should respect the comma to give "tag1" and "tag2".
We use keydown and setTimeout because keyup
works on a keyboard but not reliably on mobile.
Nonzero timeout is needed or else the comma is sometimes
inserted too late and not seen by addChip(),
tested on desktop Firefox.
The "outer" width/height functions also include padding and border. Not
including these didn't make a noticeable difference for the left/right
flipping (the omissions almost canceled each other out), but the
discrepancy is much more noticeable on the top/bottom flipping.
Use bottom: 100% to make sure the menu does not overlap the
button (as with bottom: 0). If it overlaps the button then
that interferes with the button click handler.
Previously, the comment reply form was being created entirely
client-side by cloning and modifying a <template>. This was nice because
it meant that a network request wasn't necessary to display the form,
but it also had downsides.
For example, if a topic was locked after a user had already loaded the
page (or their notifications page with a comment from that topic), they
would still be able to click Reply and type in a comment, and wouldn't
know that replying wasn't possible until they actually tried to submit
the comment.
By switching to using intercooler for this form, we can do server-side
validation to check permissions before showing the form, and it also
simplifies some other aspects, such as the warning about replying to an
old comment, which previously needed a data-js-old-warning-age attribute
in the HTML, but is now just part of generating the reply form template
server-side.
Let's try this again without the regex.
Clicking the X button in an autocomplete chip could inadvertently remove
the wrong tag (and cause a weird "merging" behavior) if another tag
ended with the same text as the one being removed. For example, if a
post had both "one.two" and "two" tags and you clicked the X button on
the "two".
Clicking the X button in an autocomplete chip could inadvertently remove
the wrong tag (and cause a weird "merging" behavior) if another tag
ended with the same text as the one being removed. For example, if a
post had both "one.two" and "two" tags and you clicked the X button on
the "two".
This also removes the attempt to close the dropdown if you the toggle
again while it's already open, since it seems like that isn't working
correctly anyway.
Previously, the warning would only ever say "over a week old", even when
the topic/comment was much older than that. This adds a new function to
create a vague timedelta description for longer periods, and also
enables the Javascript to use it as well through adding the description
as a data attr on the reply button when a warning is needed, instead of
duplicating the logic in JS.
This is mostly just rearranging, but a couple of functional changes:
* The "preview blocks" can now be clicked to switch themes, instead of
using the dropdown menu.
* Click events should be disabled in the fake posts, so we don't need to
worry about voting/labels/etc.
The post buttons (Reply, Delete, etc.) were converted to <button> quite
a while ago, and these ones should be switched over for the same reasons
as those were (accessibility, more semantic), as well as being able to
support the error messages from Intercooler.
Previously, error messages were only shown inside <form> elements. If a
button hit an error (such as a 403 when trying to vote on a comment that
was deleted after page load), the button simply wouldn't work with no
indication of why.
This adds the error message into the <menu> containing the buttons, and
involved some reworking of the relevant JS and CSS.
The button will only appear when:
* User has the "mark new comments" setting enabled
* User has the "collapse old comments automatically" setting disabled
* The current topic has some new comments
This was previously being done a bit manually in the JS and HTML, but
CSS can handle it like this, which simplifies some things (and also
takes the +/- out of the DOM, which is probably good in this case).
If a user tries to post a link topic that's been posted before, this
will add a warning below the form with info about the previous posts and
ask them to confirm that they want to re-post. Currently, this doesn't
have any sort of time/group/etc. restrictions and will just find
previous topics from all time.
The method for doing this is a big ugly to be able to handle both the
no-JS and with-JS posting methods, but it's not too bad.
If an AJAX request ends up hitting some sort of error that hasn't been
handled properly in the code yet, it often gets a full HTML page back as
a response, instead of just a text error message. Previously, this would
end up with Intercooler putting the full text of the HTML into the error
element, which is really ugly and confusing.
Now, it will just put an "Unknown error" message, and the actual error
should still end up getting reported to me through Sentry to be able to
investigate.
Since a 413 error (Payload Too Large) is returned from nginx and doesn't
even reach the app, we need to handle this in the javascript instead of
the normal method of returning a custom error response.
This fixes the issue with previewing empty markdown (though maybe we
should really prevent that), as well as making sure they don't get a
misleading obsolete preview if they lose internet or something similar.
Now that we have the Edit/Preview tabs, having another line of text
above that feels pretty excessive. There are still some awkward uses of
this though, and the field should probably have a <label> element
regardless, so this will likely need some revisiting.
Since tags are all lowercase, no suggestions would be found if the user
typed in any uppercase letters. This converts to lowercase and fixes
that issue.
Previously, the autocompleting tag input would only actually submit the
tags that had been converted to "chips". This meant that if the user had
a "leftover" tag that they had typed in but not actually converted to a
chip (by typing a comma or using the autocomplete dropdown), it would be
lost when they submitted the form.
This appends it to the tags before submitting, so that it's not lost.
A user with JS disabled can submit new topics, but the autocomplete
behavior was making it so that their tags were lost, because the "real"
tags input was a hidden one that was only updated by JS.
This starts the original (visible) input out as the tags one, and has
the JS move it over to the hidden one, so it will only happen if they
have JS enabled.
If the user has text selected inside a comment when they click the reply
button, this will automatically start off the form with that text inside
a blockquote. This only works if the selected text is inside another
comment (for example it won't work if the text is in the sidebar or the
topic itself), and only if the entirety of the selection is inside the
same comment.
This is a change I've been meaning to make for a while anyway for better
semantic HTML and accessibility, and it ended up being necessary to be
able to support some other updates as well.
This button only shows up on mobile (or small screens) and will appear
after the user has scrolled down at least two viewport-heights. The
Intersection Observer API is used to detect this with an invisible
"buffer" div, instead of attaching to scroll events.
When a user enables one of the user settings that causes external links
to open in new tabs, we should be adding rel="noopener" to the links as
well, for security reasons:
https://mathiasbynens.github.io/rel-noopener/