We now track our inbound timing events using code in
typing_data.js.
This code may be a little more robust with variations on how
recipients are represented in events, although there are no known
bugs here.
This change moves most of the logic related to starting and
stopping outbound typing indicators to a new module called
typing_status.js that is heavily unit tested.
While this was in some sense a rewrite, the logic was mostly
inspired by the existing code.
This change does fix one known bug, which is that when we
were changing recipients before (while typing was active), we
were not stopping and starting typing indicators. This was
a fairly minor bug, since usually users leave the compose
box to change recipients, and we would do stop/start under
that scenario. Now we also handle the case where the user
does not leave the compose box to change recipients.
Previously, we would let the backend pick a color and send it to the
frontend; then the frontend would ignore that color and pick a
different color and send it to the backend, which would in turn resync
to us.
Fixes#3572.
Fixes#3858.
This fixes two bugs:
* If a user is not subscribed to a default stream, he or she would not
be have the option to invite users to that default stream.
* The initial streams checked in the invite modal were the
non-invite-only streams the user was subscribed to, not their
default streams.
Fixes: #4209.
The old code may have had some subtle bugs related to sorting of
ids or stringification or failed Dict lookups. The new data
layer should be more robust. We had some tracebacks recently
from the old code, and they should go away now.
This fixes the styling to stay on the screen of most reasonably sized
monitors along with extending the JavaScript code to allow for the
video to be keyed to in the lightbox.
This fixes the hubot text that still stays when you transition to
integration details along with fixing the first animation that is
choppy and previews briefly before fading in.
Fixes#4210.
Replacing file input doesn't work for value clearing. The best
way is to clean value directly, which excludes accidentally adding
wrong file after upload-widget validation error.
This makes it much more convenient to close the emoji reactions
popover after opening it with the hotkeys.
It'd be great if we had a test suite for escape so that we could add
tests for this.
Fixes part of #4197.
This is kinda hacky and probably not how we want this to work
long-term, but I think it's a larger refactoring project to make this
part of the model make sense.
Checking by href is a flawed approach due to the fact that hashes
are included in the href and will throw off the results of
returning the last block in a path. The window.location.pathname
property is a much better indicator of the current path.
If a url is present in stream description, it will be
rendered as a clickable link under /streams page.
Tweaked by tabbott to use the separate rendered_description element to
avoid duplicate rendering and to live-update.
Fixes#1435.
iOS doesn’t seem to play nice with the web socket library we are using
them, so disable use of websockets for sending messages until we can
fix that.
Fixes#2306.
Instead of passing in a hash to template whose keys are a
mixture of records and strings, we now pass in an
array of records. This also removes a spurious if condition
in the template that was a result of the janky data structure.
We were incorrectly appending all the emoji into the emoji picker
every time it was opened, rather than just once.
Note by tabbott: Arguably this isn't the right fix, in that it might
be better to just render the emoji picker once at the beginning. But
this definitely fixes the bug.
Fixes#3952.
This was regressed in 89e17e1aee.
At least one of the symptoms was that we weren't updating the
activity list properly. This could also cause tracebacks in
compose fade logic.
This adds an image feed that you can scroll through with hotkeys
in the lightbox.
The left and right arrow keys along with the left and right arrows
will go to the prev/next image, and clicking on an image will also
take a user to that image.
This fixes a bug where newly received very-long messages would only
sometimes be collapsed properly until a second message arrived
(whether it did the right thing dependened on whether the new message
had the same recipient or a different recipient from other arriving
messages).
Apparently, we correctly called condense.condense_and_collapse in all
but one of the codepaths of `render` that add new messages. This
adds a call on the missing codepath.
Fixes#3978.
This adds an organization description field to the Realm model, as well as
an input field to the organization settings template. Added three tests.
Set the max length of the field to 100 characters.
Fixes#3962.
On realms with ``should_list_all_streams() == False``, previously, we
would subscribe a user to a stream, but also incorrectly show the stream
creation dialog.
Instead, we act as if the stream was newly created.
This change makes our dependency on compose.stream_name() happen
in sort_recipients, so we compute it only once, and we can
more easily break the circular dependency.
This also fixes the error associated with view on toggle deactivation.
Now, on deactivating a bot, the bot-name and bot-email should strike-out.
And on reactivating a bot, the bot-name and bot-email should remove strike-out.
Toggle edit button on bot activation/deactivation.
Fixes#3413.
Send typing notification events when user types in the compose box.
Listen for these events and display a notification.
Sending notifications: Notifications are throttled, so that start
notifications are sent every 10 seconds of active typing, and stop
notifications are sent 5 seconds after active typing stops or when the
compose box is closed.
Displaying notifications:
When a typing notification is received, if the current narrow is private
messages or is: pm-with and the user is not the sender,
"Othello is typing..." is displayed underneath the last message. This notification is
removed after 15 seconds. If another notification is received during this period, the
expiration is extended. When a stop notification is received the notification is removed.
Internally, a list of users currently typing is maintained for each
conversation (in a dict). When an event is received the list (for the appropriate
conversation) is updated and the notifications template is re-rendered
based on the narrow information. This template is also re-rendered when
the narrow changes.
Significantly modified by tabbott for clarity.
Fixes#150.
We now correctly pass the list item for a user to the function
compose_fade.update_one_row().
This regression started happening in the recent commit of
eece725073. Before that commit,
compose-fade was broken in a different way.
Testing this fix requires creating a stream and opening the compose
box in one window. Then, in the other window, have a user not
subscribed to the stream log on for the first time. Be careful
to make sure you flip back to the other browser tab quickly, and
you should see the new user grayed out. (You can get a false
positive if you wait too long, because the periodic update was
correctly fading before this fix.)
This fixes the a call being made in ui.js that prevents all scroll
events from occurring while a modal is displayed.
This used to be necessary back in 2012 as modals didn't require
scrolling and would affect background scrolling, however it isn't
required anymore.
Our JS/CSS now only uses the user-fade class for elements
that have the user-sidebar-entry class. This should prevent
bugs related to having doubly opaque elements.
We now have specific HTML/CSS classes for message fading and
user fading. They currently both have the same effect, changing
opacity, but we can now more easily treat them differently.
This change also removes "faded" attributes in compose-fade,
which avoids some confusion related to landing pages having
a "faded" class as well.
All open modals now should have the selector ".overlay.show",
so checking if a modal is open is as simple as checking the length
of the selection ".overlay.show".
Fixes#3655.
This consolidates all actions to close modals into modals.js and
triggers the correct cleaning/collapsing function dependent on what the
data-overlay attribute is labeled as.
It also ensures these all have an e.stopPropagation().
Fixes#4029.
This allows for users to resize the message compose box without it
collapsing back down to jQuery autosize’s preferred height.
When you hide the compose box and then re-show it, it keeps the
previous height but reactivates the jQuery module.
Fixes: #2236.
The main issue is that it wasn't doing the correct comparison; the old
logic that subtracted the viewport.scrollTop() was incorrect for how
our popovers seem to work.
Partially fixes#3741.
Previously, the code to hide "Change email" button on page load when
email changes are disabled was present in settings.js using jquery to
hide the button. Now, the show/hide is handled in the account-settings handlebars.
This fix prevents us from calling the resize library for nearly
every single keydown event in the app (ouch!). Realistically,
this performance improvement only impacts folks who turned on
the autoscroll_forever feature, but it should be a significant
speed-up for them. We should go further with this fix, but the
main damage is undone.
We simplify hotkey mappings by using different hashes for
keydown and keypress events. There are browser bugs (iOS, for
example) where keypress events have the wrong keyCode values.
This led us, under iOS, to interpret "!" as "page up."
This fix also helps us disinguish escape from shift-escape.
Brock Whittaker helped on figuring out the keypress/keydown
issues that are addressed in this commit.
Fixes#4019
We have a somewhat janky mechanism for rendering message edits,
and before this fix, we were not unblurring the text boxes when
we closed the message editing session with the escape key, which
made it so that the escape key was unusable.
We had some ancient logic for typeaheads that was supposed to be
Firefox-specific, but I can't reproduce the code even running under
Firefox, and even if it did, it was returning true instead of false
for a long time, so I suspect the code has been wrong/irrelevant for
a long time.
When checking for hotkeys related to popovers, we avoid making
the external call for keys that won't be important for popovers.
This mostly helps testing.
Only check to see if the compose send button is in focus if
we dealing with backspace/shift_tab. As the comment notes here,
these sections of code are somewhat dubious.
This was originally introduced in
025b79d98b, which is far back in ancient
history when compose had a different shape (predates enter-sends,
too), and regardless, this code never affected anything but zulip.com.
This fixes the mobile web experience for Chrome on iOS.
Apparently, Chrome-on-iOS silently has a `viewport` module that
overrides and user-defined module by that name, causing all of our
code that accesses the viewport module to not work on that platform.
We fix this by renaming it.
Using this UI, a user can now reactivate the bots owned by him.
Until now if a bot was deactivated, there was no way to use the
old bot's original email address. But now they can be reactivated
and their email can be reused.
Fixes: #1183.
This adds a button to #subsciption page called "View Stream"
that narrows the user to that particular stream.
This fix involves typical changes to JS/CSS to add new features,
and we also add a "preview_url" field to the sub object in
stream_data.js.
Fixes#3878
This fixes a regression introduced in
8801158dfd.
Apparently the `page_up`/`page_down` hotkey definitions somewhat
confusingly called `spacebar` `page_down`, etc. Probably worth doing
further cleanup on this.
Introducing the level function makes it a bit more clear that active
users get sorted to the top.
It also shaves a couple milliseconds for large buddy lists, although
that is mostly negligible compared to name sorting and rendering.
It's easier to reason about the activity.js code if we just
make it clear that presence_info is a global singleton. Going
forward, functions that use that data will explicitly refer to
exports.presence_info.
This change makes some tests slightly more awkward to set up, but
with the actual code you now don't have to question whether there
are multiple copies of presence_info to maintain.
The diff for compare_function is a bit confusing to read, but it's
basically just de-dented since we don't need to parameterize the
compare function any more.
The function focus_lost() was setting has_focus to false
in all cases; now it does it more clearly. I also added a
comment explaining why we don't ping on losing focus.
We no longer build the buddy list twice during page load; we
build it just once from page_params information. (We also send
the initial ping and schedule subsequent pings slightly later in
the process.)
We also don't do redraws upon regaining focus, since we don't
show ourselves in the buddy list, and even if we did, we wouldn't
need a full server update.
To have this flexibility, we introduce the want_redraw flag to
focus_ping.
- Add settings parameter for max realm icon size.
- Add settings parameter for max user avatar size.
- Add checking file size to avatar and icon
uploading views.
- Transfer file size limit parameter to frontend.
- Add tests.
- Change templates/analytics/stats.html to use 'Last
Week', 'Last Month', 'Last Year' time ranges instead
of 'Last 10 days', 'Last 30 days'.
- Change static/styles/stats.css to not set background
color for default time option, for messages sent by
client and message by recipient type.
- Change static/js/stats/stats.js to show only available
time range options, and set background color for the
default. The default is Last Month if it exists, and
otherwise All Time.
Fixes: #3856
This refactors the .message_controls to stop relying on absolute
positioning and strange CSS, and throws them inline.
This also restyles so they hang to the right of the time which is now
always present.
Fixes: #3761.
This module handles the popovers in the stream list--one for
stream actions and another for topic-specific actions.
The extraction was mostly straightforward, but I did move some
of the code related to the color picker to be more consistent
with how I organized the other click handlers.
We pass in sub instead of stream_name, to support callers that
already do lookups by stream id.
And then we make the second optional argument be subscribers, since
that is all we were using from the old `attrs` argument.
When possible, we should use get_sub_from_target() instead of
get_stream_name(), not only because it often saves a lookup later,
but it also makes it easier to audit the code for name vs. id
bugs. (When you rename a stream, there can be races where you
use the old stream name instead of the more durable stream_id).
This commit handles the easy cases where the caller directly
wanted the sub, not the name.
A clear-search option to clear the user-list searchbox has been added.
This feature was present in the main searchbar but absent elsewhere.
Fix a part of #3716.
We had a theory that get_user_id() errors were often due to race
conditions related to reloads, so we would only report missing
user ids if subsequent lookups failed 5 seconds later. It turns
out we still get the blueslip errors, and now we don't get
meaningful tracebacks. This change makes it so that errors
get reported immediately again.
If we get invalid events related to stream subscribers, we now
exit earlier to prevent ugly tracebacks. We may eventually
want to upgrade some of these warnings to errors, once we fix some
of our live-update bugs. In particular, we don't yet live-update
users when streams go from private to public, so if you add/remove
subscribers to a newly-public stream that a user still thinks is
private, they will not be able to handle the event through no
fault of the codepath that happens during the add/remove.
This currently only supports this in emoji reactions, not in actual
emoji in message bodies, but it's a great start for people who want a
text-only view.
Tweaked to update the text by tabbott.
Fixes#3169.
We have special code for closing a "compose preview", but
it should only apply to the enter key. Before this fix, we
would do the "enter" logic for other hotkeys like "j".
If you are typing a key like "q" in the compose box, there is no
need to check if the home tab is obscured, because the effect of
"q" is not limited by the message pane being opened.
This saves a bit of unnecessary computation when you type
non-arrow keys, which is especially important in the compose
box for characters that seem ordinary, like "j" and "q", but
which have mappings in some cases.
I noticed while reviewing #3807 that we still haven't fixed this;
because timestamps are primarily displayed in the message view, fixing
this is trivial.
Apparently, our logic was broken on systems where altKey and metaKey
are different, because we didn't ignore hotkey combinations that
included altKey.
Fixes#3738.
Change `from django.utils.timezone import now` to
`from django.utils import timezone`.
This is both because now() is ambiguous (could be datetime.datetime.now),
and more importantly to make it easier to write a lint rule against
datetime.datetime.now().
Add neccesary UI in #administration and #settings for
changing the bot owner. The bot owner select control
is rendered dynamically in order to avoid performance
issues in case of large number of users.
Fixes: #2719.
Previously the mechanism worked such that the innerHTML was being
appended to directly potentially thousands of times which has horrific
performance implications. By concating all the strings together before
appending to the HTML it all gets rendered in one chunk without forcing
a re-render of previous elements. Performance is ~15x-20x faster now.
Use `name_to_codepoint.json` file (and the similar structure in
emoji_codes.js) to map emoji names directly to codepoints and change
the rendered emoji image to `unicode/<codepoint.png>` rather than
`<emoji_name>.png`.
Fixes: #3539.
If you send a group PM from the home view, and then one of the
recipients changes their email, and then you send a group PM
to the same recipients, we need to make sure we don't create
a spurious recipient bar. This fix makes this happen by
changing util.same_recipient() to look at user ids instead of
emails.
Using stream_id in recipient comparisons fixes a
bug in this scenario: go to home view, send message
to stream, wait for admin to rename stream, send
another message to the stream. Before this change,
the stream name would live-update but you'd get a
spurious recipient bar due to the prior message still
having the old stream name in places internally.
There were other ways to fix the live-update glitch,
but it's just generally cleaner to do stream id
comparisons.
Part of this change is to add stream_id to
compose_fade.set_focused_recipient().
Change the remaining "Admin settings" with a button, namely
changing a stream's privacy, to instead be a "[Change]" link
opening a confirmation modal.
Fixes: #3493.
This changes the time render to be done on the client-side and
therefore take advantage of knowing the client’s timezone, along with
being formatted in a more human-parseable way.
This changes the layout of administration for non-administrators such
that they can view organization settings and emoji settings and
displays everything as readonly unless they have the capability to edit.
For now, we just enabled this for the emoji settings and organization
settings features.
This removes all the .expectOne statements and replaces with a
single broad stroke .hide() that doesn't check if they exist,
but rather just ensures they are hidden by default until triggered.
This adds to Zulip support for a user changing their own email
address.
It's backed by a huge amount of work by Steve Howell on making email
changes actually work from a UI perspective.
Fixes#734.
* Created a drafts modal to display/restore/delete drafts
* Created a Draft model to support storing draft data in localstorage
* Removed existing restore-draft functionality
* Added casper and node tests for drafts functionality
Fixes#1717.
We now sweep all active messages for avatar changes and update
the message items and re-render, rather than patching the
DOM. This avoids some quirks that happen when subsequent messages
get sent and we re-render previous messages out of the message
store.
Our approach here is similar to how we do full-name updates.
In f75af94984 I added some
lines of code that made it so that live updates for avatar
urls would affect messages currently in the browser.
This change worked well when the live update actually happened,
but then the next time the user would reload, the avatar in
the message pane would regress back to showing the avatar urls
from the server (which could have caching issues of their own).
This fix removes a couple lines of code that had the intended
effect of making all of your messages from any given sender
show the same url (good) but which generally grabbed
the url from an old message (bad).
After this fix, we go back to having old messages possibly
showing the old avatar urls, but new messages will display the
new avatar.
(There are lots of moving parts in the avatar system, because
not only do browsers cache image urls, but our server caches
messages and recipient info, so there have been "fixes" to
avatars since this change that are valid fixes in their own
right but not directly relevant to this commit.)
The current logic that we have is as follows:
* If a message is locally echoed, the draft is stored via the locally
rendered message, and that system takes care of it. So no need to
store it here.
* If the message isn't locally echoed, we don't close the compose box
until, so the content is safe here as well. It'll be saved as a draft
if the compose box is later closed due to a failure sending.
This replaces the settings toggle which had the same markup as the
current component toggle, but not the same JavaScript, along with
having an issue with inline-block spacing, with the new JS generated
one.
We now call activity.build_user_sidebar when we initialize
the user sidebar, which avoids some janky jQuery code
that was intended for partial updates.
With 2000 users in dev, the amount of time to build the sidebar
decreases from 1100ms to 700ms in my tests. (Times vary a bit,
but it does seem consistently faster now.)
Activity.update_users() is still used to handle partial
updates of users in the buddy list, but now all the places
that want to re-build the whole widget go through
build_user_sidebar().
The pinned streams were sorted in alphabetic order (i.e. Verona appears
before devel). The reason is that after we plucked pinned streams out from
stream_data.subscribed_streams(), we didn't sort them again, so they
remained in the alphabetic order used in stream_data.
However, we did sort unpinned streams explicitly by using custom compare
function in stream_list.js (by default sort by lowercase stream name,
but when there are more than 40 subscribed streams, sort active streams
first). That's why this issue only relates to pinned streams.
Changes were made to sort pinned streams by lowercase stream name, always,
whether they are active or not (different from unpinned streams).
Tests were added to ensure this overall sort order is correct, i.e.
1. pinned streams are always sorted by lowercase stream name.
2. pinned streams are always before unpinned streams.
3. unpinned streams are sorted by lowercase stream name, if there are more
than 40 subscribed streams, sort active streams at the top, among active
and inactive streams, still sorted by lowercase stream name.
Fixes#3701
User search for streams will now return results where the stream
description (but not the stream name) include the string in the
user query.
The filtering process first obtains the streams whose names match the
user search query, then sorts and displays them. From the remaining
streams, it obtains streams whose description matches the query and
displays them in sorted order after the name match results. Other
streams are not displayed.
Fixes: #2674.
When an admin deactivate a stream, we now remove the
appropriate row from the default streams tables for other
folks viewing default streams in the admin tables.
We add a default_streams_table() function that builds an
object encapsulating the defaults streams table in the admin
system.
This function allows us to simplify the click handler code by
closing on row/stream_name rather than picking those values out
of the DOM.
Fixes#268.
Modified significantly by tabbott to:
* improve code cleanliness / repetition
* add missing translation tags
* move code into message_edit.js
* correspond with the new backend.
* not display the option for messages only topic-edited
The new behavior is:
(1) If enter-sends is enabled, just send the messsage.
(2) If enter-sends is not enabled, return focus to the compose area.
Based on great work by khantaalaman in #3673.
Fixes#3489.
This is a fairly risky, invasive change that speeds up
stream deactivation by no longer sending subscription/remove
events for individual subscribers to all of the clients who
care about a stream. Instead, we let the client handle the
stream deactivation on a coarser level.
The back end changes here are pretty straightforward.
On the front end we handle stream deactivations by removing the
stream (as needed) from the streams sidebar and/or the stream
settings page. We also remove the stream from the internal data
structures.
There may be some edge cases where live updates don't handle
everything, such as if you are about to compose a message to a
stream that has been deactivated. These should be rare, as admins
generally deactivate streams that have been dormant, and they
should be recoverable either by getting proper error handling when
you try to send to the stream or via reload.
(There was a method with the same name before, but it wasn't
being used. The new version will accept stream_id instead
of name, and we will use it as part of deactivating streams.)
We already do detection of the client on the backend based on
User-Agent and the fact that it's a JSON view, which is pretty safe.
This fixes an issue where the server was not treating the Electron app
as its own client.
This significantly simplify the logic for our logging process, making
it the case that websockets message sending requests always are logged
as having the exact same client as a normal AJAX request from that
server.
This prevents users from either dragging formatted markup into content
editable boxes or pasting it in. This uses the “input” event rather
than “paste” because “paste” does not have the end result of the
contents whereas “input” does.
This is not a security vulnerability as it may seem. Processing on the
backend sanitizes input if it contains HTML.
We use to have client-side logic that would append timestamps
or random numbers to avatar URLs to force browsers to
refresh their cache.
We no longer need this now that the back end maintains
versions for avatar changes and puts the version in the URLs.
When we process messages for unread counts, we now call
people.pm_reply_user_string() to get a string of user ids,
rather than using emails that may have changed since the
message was originally created.
There is a particular case in which when a user clicks on a tab, then
uses the goto method to go to another, and then clicks on the original
tab again, it will not load the original tab. This is due to the fact
that the goto function that is used to navigate to a tab without
clicking does not set the last_value, therefore leaving a state that is
incorrect and denying a view update in the case that a user performs
the following:
Click B -> Goto A -> Click B
In this case, it saves the last_value as “B” and so when a user clicks
back on “B” it does not trigger any change as it thinks the user is
going from “B” to “B”.
For our user administration, we now primarily work with user ids
that get put into data-user-id attributes. We still put emails in the
tags to make our Casper tests easy to maintain.
This requires a minor change to the back end to pass down user ids
for the /users endpoint (in get_members_backend).
Like the topic edit pencil icon, the new UI is mostly invisible, but
appears when you hover over the recipient bar.
* Added a tag to hold the mute button in recipient_row.handlebars with
corresponding styling in zulip.css.
* Added an event handler for the mute button in click_handlers.js.
Fixes: #2235.
When we get notified of an email change and the compose box is
open for PMs, we should update the email in the compose box.
This helper will be useful when we start handling such events.
We now convert our pm-with search operand to a list of user ids
for matching against messages, rather than using emails. On the
message side we look at user ids from display_recipient.
This replaces the bootstrap default modal footers that have a
[data-dismiss] button with an .exit button in the top section of the
overlay that is styled congruently to the current subscriptions page.
This adds usage notes and comments to the component.toggle class
to make it more readable and usable for those who are unaware with
the prototype of the class or how to create a new instance.
API: Adds a "display_order" to the response, which is a suggested order of
importance for the clients or recipient types respectively.
frontend: Changes messages_sent_by_{client,recipient_type} to use a fixed
order for any given user.
Also includes a number of changes to messages_sent_by_recipient_type that
were convenient to do at the same time, since the two charts share a lot of
code.
In preparation for turning messages_sent_by_client into a bar chart.
This removes the "pie-specific" pieces from the functions used by
messages_sent_by_{client,type}.
This makes the subscriptions page responsive by having the settings tab
slide over when a user taps on a stream, giving almost the whole screen
to view the settings.
Previously, set_muted_topics was calling update_unread_counts once for each
topic in the input; this results in poor performance when there is a large
number of muted topics.
Fixes: #3605