This PR implements literal emoji match in the emoji picker (for reactions)
and in emoji typeaheads (in compose box)
Tested on mobile browser by opening the emoji picker with the
reaction button, selecting an emoji via the native keyboard, and
ensuring the selected emoji appears in the emoji picker’s search
result.
Fixes#21714.
This makes this function easier to reason about, by having only one
version of the query floating around.
The change is nearly NFC: the one other place this `query` parameter
is used is the `triage` function, and that already lower-cases the
query too.
But `triage` has some additional case-related behavior: among prefix
matches (but not among exact matches), it moves any that match
case-sensitively ahead of any that don't.
As long as all emoji names are lowercase -- as all our built-in
emoji are, and as all custom emoji probably are in most realms --
that still has no effect: either the query is lowercase too and all
matches are case-sensitive matches, or it isn't and none of them are.
But it can show up if someone adds a custom emoji like `:GitHub:`
or `:LaTeX:` (like we have a `` in chat.zulip.org), and then
someone does the natural thing of searching for them in lowercase.
When the behavior does show up, it seems like it can only come
across to the user as a glitch: the emoji that have capital letters
get weirdly taken out of order and moved to the end, or just don't
show up if there are more than 8 results.
In general I'm not convinced there are any situations at all where
this behavior of `triage` makes sense: basically every other
search UI in the computing universe is case-insensitive except for
some aimed at programmers searching through code, and none of our
typeahead searches are aimed at doing that. But for the moment,
just simplify the emoji case in particular.
For example, if a user's name is "Simon Peyton Jones", we'll already
match that name on the queries "Pey" or "Peyton", as well as on
"Simon P". We should do so on "Peyton J" or "Peyton Jones", too.
Similarly, if the user is looking for an emoji of a face in the moon
and they start by typing ":moon", we'll show them both 🌝 "moon face"
and 🌚 "new moon face", along with some other moon-related results.
If they go on to make it ":moon " or ":moon f", though -- as one very
naturally would in order to eliminate things like "waxing moon" and
"moon ceremony" -- then we mysteriously eliminate 🌚 "new moon face".
Instead, the query "moon f" should match both 🌚 and 🌝.
Found this while comparing the web/shared implementation with the
mobile implementation of emoji search. The new behavior here
reflects what we already do for emoji search in mobile, both in the
compose box's typeahead and in the add-a-reaction screen. The
existing behavior here seems pretty annoying, so fixing it will be
part of switching on mobile to the shared code (zulip/zulip-mobile#4636)
without regressing the user experience.
The current behavior was introduced, more or less, in 245d65eb9; then
revised in 5edbcb87f to make the logic more clear, and a fix made in
542f4766d, all 2018. The PR thread was #8286, following issue #8279.
The old behavior before those changes was pure substring matching,
plus a trailing space was ignored (which is the part the issue was
about.) None of the discussion touches on this question; as far as I
can tell, the fact that "Peyton J" doesn't match "Simon Peyton Jones",
nor "moon " match "new moon face", was entirely an unintentional
side effect of those changes.
This reverts commit a8fd535955.
This reverts commit 944781e873.
In an attempt to introduce code from mobile into web to match literal
emojis, the author inadvertently introduced a buggy and smelly change.
Probably best to leave the implementation of this in mobile where there
is more context about the shape of the emoji object available. Web
doesn't actually benefit from the additional behavior anyway.
See https://github.com/zulip/zulip/pull/21723#pullrequestreview-937051603
There is no guarantee that the code passed into parse_unicode_emoji_code
is valid unicode. In the case that it is not, it might be better to
return undefined instead of throwing an exception: to represent a
non-parseable code.
For context, mobile currently returns custom emojis as emojis with
string names in their code property, instead of actual unicode.
This PR implements checking for a literal emoji match in emoji
typeaheads. In other words, if you paste or type panda face into an
emoji typeahead, panda face should be presented as an option to choose
from.
This behavior is currently present in the mobile app, adding it to
shared will enable both platforms to utilize this logic.
The mobile app was never able to use the shared
version of emoji.js, because, among other problems
with our code organization, the emoji.js module
is strongly based on a mutate-the-data paradigm
that doesn't play nice with React. The way
that we mutate data and violate encapsuation
here is something that we would mostly want to fix
without even trying to shared code with mobile, so
subsequent commits will try to extract some pure
functions into a shared module.
We have two different frontend implementations of computing the
un-resolved form of a topic name, and they have a subtle -- but
intentional -- difference in behavior.
Factor them both out into the resolve_topic module, along with
their inverse, and with comments and tests.
Because Zulip Mobile supports some older iOS browser versions that
don't have replaceAll support yet, and mobile is averse to doing the
infrastructure work required to add a, polyfill we avoid using them in
the shared module for now.
See https://caniuse.com/mdn-javascript_builtins_string_replaceall
It's 2022 and the WHATWG no longer recognizes the term URI. Everything
is now a URL or a type of URL. Which is great because it's way less
confusing. Details here:
https://url.spec.whatwg.org/
Moves hash_util.by_stream_uri and hash_util.by_stream_topic_uri to
internal_url so they can be used by external codebases. Due to these
functions being called in many places in the web codebase, wrappers
for both functions are left in hash_util in order to keep these
calls simple.
Also adds test for explicitly testing each function.
Move hash_util.encode_stream_id to internal_url, so it can be shared
with external codebases. Also add a test that explicitly tests escaping
special characters in stream names.
Move stream_data.id_to_slug to internal_url, making it shareable. The
function has been renamed to stream_id_to_slug to reflect that it
operates on a stream id.
Moves the encodeHashComponent and decodeHashComponent functions out of
hash_util and into internal_url which belongs to shared. This is to
accommodate sharing of this code with mobile or any other codebases that
do not wish to duplicate logic.
Previously, if a user had a realm emoji set as their status emoji and
someone deleted the realm emoji, the app would fail to initialize,
because of the error we throw from `./shared/js/emoji.js`.
This commit fixes this by just displaying the deactivated emoji,
similar to how we do when realm_emoji used as reactions are deleted.
As part of the fix, we add a function get_emoji_details_for_rendering,
which duplicates some of the logic used in `reactions.js`, we can
refactor to remove the duplication in `reactions.js` in future
commits.
Note that the following behaviour is a part of our design:
If a user sets their emoji to a particular realm emoji, say for
example "octo-ninja", and "octo-ninja" was then deleted, and a new
emoji was added with the name "octo-ninja", the user's status emoji
would change to show the new emoji instead of the deleted emoji.
Also note that in the `user_status.js` node test, we were able to
change the name for the 991 realm_emoji because it had not been
previously used anywhere in the test (possibly added as just a copy
paste artifact?).
Fixes: #20274.
emoji: Use reaction_type parameter to analyze emoji.
This commit changes the behavior of how we show
animated emojis in the buddy list. We now show still
image of animated emoji and when hovered show the
animated emoji.
Fixes#19521
We only need to bump up indexes if inbound
events suggest that we have incremented our
personal index from another device.
We don't want somebody else's runaway index
to affect our index.
(For both widgets the sender_id is part of
the key, so uniqueness across all senders is
not required for the integer part.)
We now ignore question edits if the sender of the submessage
is not the message author.
The webapp UI prevents folks from editing the question for
somebody else's poll, but a determined person could use our
low level API to do it. We will add safeguards on the server
side for this, but this change is sufficient to protect the
webapp (and mobile when they upgrade the library).
When a user entered an invalid character (whitespace or characters not
present in a name), the cleaned-up array, and hence the query,
would be empty which resulted in an error.
Fixes#17542
Previously, exact matches could be pushed off the typeahead list in the
case where there were more prefix matches that happened to rank first,
which is confusing to the user: if an emoji, for instance, falls into
this category, it will never show up in typeahead, which is easy to
confuse with the emoji not existing.
This isn't a perfect fix — there are still cases where it's hard to find
emojis because the prefix-space is very crowded, but it does fix a
category of surprising and frustrating behaviour.
This doesn't come completely without downside - it means that the exact
match emoji will jump to the front of the list, which changes what is
currently conceptually a "filtering" operation to a "filtering and
sorting" operation, but it seems on the whole to be a more ideal
experience. This is particularly notable in the non-typeahead emoji
picker, which uses the same codepath, but this change seems somewhat
desirable even there, since it allows the user to type the name of an
emoji and press enter and have that emoji show up, without having to
visually confirm that they aren't inadvertently selecting a
prefix-matching emoji.
A better solution to this in the long term might be ordering emoji
results by shortest-first as a tiebreaker for alphabetical ordering,
since that should provide the same behaviour while keeping the mental
model as "filtering" (since the sort order won't change as the user
types), but this seems like a reasonable first pass, and changing to
shortest-first ordering after making this change won't break any muscle
memory for existing users.