Commit Graph

444 Commits

Author SHA1 Message Date
Rohitt Vashishtha 62007d3e38 compose: Do not show compose-invite-users row for silent mentions. 2019-02-22 13:17:47 -08:00
Vaibhav 24445309e2 compose: Extract `render_and_show_preview` function.
This adds a function that controls the whole process of applying
markdown and displaying the markdown rendering preview on request;
This is required to avoid code duplication when adding preview feature
to message-edit UI.
2019-02-05 11:31:56 -08:00
Abhinav Singh e7c8077abc edit: Add support for using video call link in message edit.
This code will correctly add video call link to the message
textarea based on whether 'Add video call' was selected from
message composition form or message edit form.

The implementation was semi-rewritten by tabbott to remove an
unnecessary global variable, with fixes for the unit tests from
showell.

Fixes #11188.
2019-02-02 11:03:31 -08:00
Marco Burstein 9ddadd39f4 compose: Add support for using Zoom as the video chat provider.
This adds Zoom call properties to the `Realm` model, creates endpoints
for creating calls, adds a frontend and tests.

Fixes #10979.
2019-01-07 10:00:02 -08:00
Vaibhav 93914d8cd8 markdown: Parse '/me' for multi-line messages.
Previously, messages with more than one line did not parse '/me' at
the beginning of the message.  Since there's a reasonable way to
render multi-line messages, this commit adds support for doing so.

This change does potentially break with the expected behavior of other
slash commands, but it seems worth providing useful functionality over
a blind focus on consistency.

Fixes #11025.
2018-12-29 15:32:50 -08:00
Steve Howell 4e0969bb49 Rename util.set_topic -> set_message_topic(). 2018-12-29 11:38:39 -08:00
Steve Howell 35b904b184 subject -> topic: Fix subject in opts.
It's kinda difficult to track down all the interactions
with the opts that go through compose_actions.start(),
but I think I got everything.
2018-12-16 11:26:18 -08:00
Steve Howell d7c2577ffb subject -> topic: Rename compose fields.
The stream/topic edit areas now have these ids:

        #stream_message_recipient_stream
        #stream_message_recipient_topic

They are pretty verbose, but being able to grep
for these without noise does have some value.
2018-12-09 21:28:45 -08:00
Tim Abbott d0f71881f4 docs: Add detailed documentation on the process for sending messages.
This has long been something missing from our suite of documentation.
2018-11-29 16:25:35 -08:00
Steve Howell 82b9f2a3db subject -> topic: Fix create_message_object(). 2018-11-16 11:11:40 -08:00
Rohitt Vashishtha d7a0bd4a6c subject-to-topic: Add topics to compose_state.js. 2018-11-14 23:24:06 -08:00
Yashashvi Dave f6b4e65b92 compose: Hide sub-btn in compose-to-unsub warning if user can't subscribe.
Hide subscription button in compose-message-to-unsubscribe-stream
warning, if user can't subscribe back to stream.
2018-11-02 11:57:04 +05:30
Shayan Toqraee a4b14b8526 compose.js: Move set rtl logic to keyup event.
This fixes an issue where the ltr/rtl translation lagged one character
behind as a user typed.
2018-08-14 11:41:53 -07:00
Marco Burstein 4dbf59dbaa compose: Create a separate "New stream message" title editing function.
To reduce code duplication, create a new function for editing the
"New stream message" button title.
2018-08-13 15:08:15 -07:00
Shubham Padia e21e8c1bae compose: Hide subscribe button and change text for waiting period users.
Fixes #10124.
Users in the waiting period category cannot subscribe other users to
a stream. When a user tries to mention another unsubscribed user, a
warning message appears with a subscribe button on it to subscribe
the other user.
This commit removes the subscribe button and changes the warning text
for users in the waiting period category.
2018-08-13 10:18:35 -07:00
Shubham Padia 3f019cafb2 compose: Improve error handling when subscribing other users to a stream.
Instead of displaying a fixed error message inside the yellow bar itself,
now the yellow bar disappears on error and a red compose_error is shown.
The error message is the one returned from the server.
2018-08-13 10:18:35 -07:00
Marco Burstein 6f14f4f047 compose: Update the `New topic` button to `New stream message` in PMs.
If a user is narrowed by `is:private`, `pm-with`, or `group-pm-with`,
change the `New topic` button to say `New stream message` instead for
added clarity.

Also, add to the Casper and Node tests for this behavior.

Fix #9072.
2018-08-09 08:55:01 -07:00
Yashashvi Dave bbe326dd29 message edit: Add markdown shortcuts to message edit UI.
This makes the ctrl+B, ctrl+I, ctrl+shift+L shortcuts available when
doing message editing.

Fixes #9917.
2018-07-23 10:41:46 -07:00
Yashashvi Dave 987c4f7df3 static/js/compose.js: Clean `add_markdown` function.
Rename `add_markdown` function to `wrap_text_with_markdown` and
use closure variables in function `wrap_text_with_markdown`.
2018-07-23 10:38:18 -07:00
Steve Howell 5db9b7a2ba refactor: Extract rtl.set_rtl_class_for_textarea().
We can now theoretically use this for any textarea
that supports our markdown (besides the compose box),
plus we keep the RTL code a bit more self-contained.
2018-07-11 19:20:22 +05:30
Steve Howell ebb4b21f78 refactor: Limit scope of "range" variable.
We don't need this at outer scope, and it complicates
tests slightly.
2018-07-11 19:20:22 +05:30
Shayan Toqraee 0757d022f5 messages: Add support for right-to-left messages.
This implements right-to-left message automatic detection support in
the compose box as well as the message feed.  Full unit tests and
support in the message-editing UI are for future work (as are
potentially more fancy things like supporting things like
right-to-left multi-word names for users/streams/etc.).

Fixes #3123.
2018-07-10 10:47:56 +05:30
Armaan Ahluwalia 6d255efe4c app: Prepare JS files for consumption by webpack.
This commit prepares the frontend code to be consumed by webpack.

It is a hack: In theory, modules should be declaring and importing the
modules they depend on and the globals they expose directly.

However, that requires significant per-module work, which we don't
really want to block moving our toolchain to webpack on.

So we expose the modules by setting window.varName = varName; as
needed in the js files.
2018-07-05 10:53:36 +02:00
Shubham Dhama c6738889a9 eslint: Add and enable `space-unary-ops` rule.
Info about rule at https://eslint.org/docs/rules/space-unary-ops.
2018-06-05 00:47:35 +05:30
Steve Howell 4b2e8b83c4 slash commands: Add /ping command (via zcommand).
This adds a /ping command that will be useful for users
to see what the round trip to the Zulip server is (including
only a tiny bit of actual server time to basically give a
200).

It also introduce the "/zcommand" endpoint and zcommand.js
module.
2018-06-02 09:40:12 -07:00
Steve Howell 87ba752758 refactor: Extract compose.do_post_send_tasks(). 2018-06-02 09:40:12 -07:00
Aditya Bansal 81a677e02b reminders: Refactor relevant code to live in a separate reminder.js. 2018-05-21 09:03:31 -07:00
Shubham Padia bdda920e0b bots: Do not show `not_subscribed` warning for bots on private streams.
Fixes #9373.
`not_subscribed` warning is not shown for bots on either private or public
streams. Some of the bots have an interface such that they receive the
message mentioning them even if on a private stream where they are not
subscribed.
2018-05-18 15:24:40 -07:00
Shubham Padia 10a65a62db compose: Display error for non-admin trying to post to announce_only stream.
Partially fixes #4708.
Implements a first version (v1) for the feature. The next step would be
to allow admins to toggle `is_announcement_only` in the UI.
2018-05-16 13:35:45 -07:00
Tim Abbott 7ab8a8e820 js: Fix a bunch of indentation issues found by eslint.
This is preparation for enabling an eslint indentation configuration.
90% of these changes are just fixes for indentation errors that have
snuck into the codebase over the years; the others are more
significant reformatting to make eslint happy (that are not otherwise
actually improvements).

The one area that we do not attempt to work on here is the
"switch/case" indentation.
2018-05-06 16:25:02 -07:00
Steve Howell d4fc92c1c7 refactor: Rename method to compose_fade.update_all().
The function was misnamed before.
2018-04-28 11:15:14 -07:00
Steve Howell e5885fa8e4 Add compose.needs_subscribe_warning.
This function replaces part of compose_fade.would_receive_message(),
which has a real janky interface of returning true, false, or
undefined.

We don't need to couple the semantics of compose fading to whether
we help subscribe a mentioned user.  They're mostly similar, but they
will probably diverge for things like bots, and the coupling makes
it difficult to do email -> user_id conversions.

One thing that changes here is that we get the stream name from
compose_state, instead of compose_fade.focused_recipient.  The
compose_fade code uses focused_recipient for kind of complicated
reasons that don't concern us here.
2018-04-26 08:42:47 -07:00
Vishnu Ks c9e932a7ce settings: Add support for Hangouts as the video chat provider.
The only thing that's annoying about this feature is that you need to
be a paying G Suite customer to use it.
2018-04-23 09:39:47 -07:00
Tim Abbott dbb62ba5cb compose: Clean up variable names for preview logic.
This makes it more clear that the content has already been rendered.
2018-04-12 09:48:02 -07:00
Tim Abbott e6833b6427 cleanup: Remove the legacy Dropbox file upload integration.
This has been hard-disabled for years, we have no plans to re-enable
it, and it has some hacky code in it.
2018-04-11 11:39:48 -07:00
Shubham Dhama b650b6b38c markdown: Add @stream as an alias for @all.
Fixes: #8930.
2018-04-09 16:35:14 -07:00
Balaji2198 47f9e8319c compose: Close the compose error message box on clicking X. 2018-04-07 20:23:21 -07:00
Balaji2198 605916f6d7 compose: Add subscribe button to the not subscribed stream error message.
Before that, we needed to go the stream settings to subscribe to a
particular stream.

Fixes #3877.
2018-04-05 17:15:18 -07:00
Tim Abbott 938c4cee08 settings: Add option to control Jitsi video chat integration.
Fixes #8922.
2018-04-02 16:55:16 -07:00
Shubham Padia 077475c563 compose: Don't warn if mentioned stream members form a superset.
Fixes #8634.
Suppress private stream warning if you're to a stream whose
membership is a subset of #mentioned-stream-name.
2018-03-09 10:46:41 -08:00
Steve Howell 3a1bf04a56 compose: Add pills for typing in PM recipients.
@brockwhittaker wrote the original prototype for having
pills in the recipient box when users compose PMs (either
1:1 or huddle).  The prototype was test deloyed on our
main realm for several weeks.

This commit includes all the original CSS and HTML from
the prototype.

After some things changed with the codebase after the initial
test deployment, I made the following changes:

    * In prior commits I refactored out a module called
      `user_pill.js` that implemented some common functions
      against a more streamlined version of `input_pill.js`,
      and this commit largely integrates with that.

    * I made changes in a prior commit to handle Zephyr
      semantics (emails don't get validated) and tested
      this commit with zephyr.

    * I fixed a reload bug by extracting code out to
      `compose_pm_pill.js` and re-ordering some
      calls to `initialize`.

There are still two flaws related to un-pill-ified text in the
input:

    * We could be more aggressive about trying to pill-ify
      emails when you blur or tab away.

    * We only look at the pills when you send the message,
      instead of complaining about the un-pill-ified text.
      (Some folks may consider that a feature, but it's
      probably surprising to others.)
2018-03-07 15:53:11 -08:00
Tim Abbott 787d5c50e0 upload: Inline clear_out_file_list.
This provides a slightly clearer interface, allowing us to remove the
unnecessary split of the code for the clone_file_input concept across
multiple modules (we now just clone it on-demand).
2018-03-05 10:42:38 -08:00
Marco Burstein bdb86f1b5e emoji: Add support for translating emoticons.
Add `translate_emoticons` to `prop_types` and `expected_keys`.
Furthermore, create a emoji-translating Markdown inline pattern.

Also use a JavaScript version of `translate_emoticons` and then use
this function during Markdown previews and as a preprocessor. This
is only needed for previews, because usually emoticon translation
happens on the backend after sending.

Add tests for emoticon translation, a settings UI, and a /help/ page
as well.

Tweaked by tabbott to fix various test failurse as well as how this
handles whitespace, requiring emoticons to not have adjacent
characters.

Fixes #1768.
2018-03-04 15:37:24 -08:00
Alena Volkova e4a62aa778 compose: Add a function for handling validation errors. 2018-03-01 08:40:51 -08:00
Akash Nimare 9dba134c7a markdown: Do not use CMD+CTRL on macOS.
This fixes an issue where we allowed both the CMD+CTRL keys for our
compose markdown shortcuts.  The correct behavior is to allow either
Cmd or Ctrl, based on whether it's MacOS (Cmd) or Ctrl
(Linux/Windows), to match how those platforms work.

Fixes #8430.
2018-02-20 09:50:10 -08:00
Steve Howell 1f6ddf0110 refactor: Extract transmit.js from compose.js.
We now isolate the code to transmit messages into transmit.js.
It is stable code that most folks doing UI work in compose.js don't
care about the details of, so it's just clutter there.  Also, we may
soon have other widgets than the compose box that send messages.

This change mostly preserves test coverage, although in some cases
we stub at a higher level for the compose path (this is a good thing).
Extracting out transmit.js allows us to lock down 100% coverage on that
file.
2018-02-20 09:29:26 -08:00
Tim Abbott 6638c12aef upload: Extract feature_check helper function. 2018-02-13 14:37:26 -08:00
Tim Abbott 8836161611 upload: Refactor file upload code path to use more variables.
Now, all the various DOM elements are named by a variable, keyed off
the configuration of the upload_options object.

This is most of the work required to support file upload in the
message edit area.
2018-02-13 14:37:26 -08:00
Tim Abbott 9de7a69b13 upload: Move compose initialization back to compose module.
This makes the lines of logic a bit simpler.
2018-02-13 14:37:26 -08:00
Umair Khan c415cc74d7 validate_stream_message_address_info: Add i18n tags.
Fixes #7076
2018-02-05 16:26:24 -08:00
Umair Khan 302e106860 compose: Add parentheses for correct precedence. 2018-02-02 07:24:12 -05:00
YJDave ff8be1ac94 markdown shortcuts: Set cursor position for link insertion shortcut.
For link insertion shortcut without text selection,set the cursor
position between "[]" rather than selecting "url" in "[](url)" string.
2018-02-01 17:35:08 -08:00
YJDave dbefdad0ab markdown shortcuts: Stop triggering italic shortcut with Ctrl+Shift+i.
The Italic shortcut(Ctrl+i) should not be trigged by Ctrl+Shift+i,
since ctrl+shift+i opens the web inspector in major browsers.
2018-02-01 17:34:27 -08:00
YJDave b519f1c640 markdown shortcuts: Replace Ctrl+L with Ctrl+L+Shift for link insertion.
As Ctrl-L was interfering with browsers's Ctrl-L, the shortcut key
for link insertion is changed to Ctrl+L+Shift.
2018-02-01 17:31:01 -08:00
Weronika Grzybowska 7ac7100a1d messages: Make checking for status message consistent with backend.
Adds a check for newline that was present on backend, but missing in the
frontend markdown implementation. Updating messages uses is_me_message flag
received from server instead of its own partial test. Similarly, rendering
previews uses markdown code.

Fixes #6493.
2018-01-23 09:26:41 -05:00
Aditya Bansal 732321818d scheduledmessage: Adjust schedule_message to accept callbacks. 2018-01-19 11:33:11 -05:00
Aditya Bansal 9efc1b08a1 reminders: Add slash command to set reminders from reminder bot. 2018-01-19 11:33:11 -05:00
Aditya Bansal f272ea9087 scheduledmessages: Start using/expecting delivery_type as a param. 2018-01-19 11:33:11 -05:00
Aditya Bansal 5a794f9871 compose.js: Add schedule_message() to handle scheduling of messages.
In this we add code to support '/remind' command for causing
messages to be scheduled.
2018-01-19 11:33:11 -05:00
Aditya Bansal b71ed33e64 compose: Extract the 'Sending...' from template to be added with Js.
In this we change the way 'Sending...' is displayed. Instead of
hardcoding it into the template we make change the paradigm so
that we can have a flexible message about what's happening
rather than just always saying 'Sending...'. For eg. this will
help in the upcoming feature of Scheduled Messages by having this
message say 'Scheduling...'.
2018-01-19 11:33:11 -05:00
Aastha Gupta daf86eb664 settings: Add "text" option to emoji_set model.
We no longer have a special UI setting and model
field ("emoji_alt_code") for saying users want text-only
emojis.  We now instead make "text" be a fifth choice
for "emojiset".

Fixes #7406
2018-01-02 14:55:01 -05:00
YJDave 5ff84e97b5 markdown: Add markdown shortcuts.
Markdown shorcuts:
ctrl/cmd+b ->insert bold text
ctrl/cmd+i ->insert italic text
ctrl/cmd+l ->insert link

Fixes #5978
2018-01-02 13:48:50 -05:00
Marco Burstein e9d7161418 compose: Warn users when posting to the #announce stream.
Currently, users are warned when mentioning @all and @everyone, but not
when posting on the #announce stream. Confirm with users that they want
to send their message on #announce if over 60 people are going to be
notified.

Fixes #6928.
2017-12-20 07:36:50 -05:00
Shreyansh Dwivedi 5b49259722 compose box:Add a reply button. Fixes #5578 2017-12-15 14:23:24 -05:00
Tommy Ip 6e22847548 refactor: new message content -> compose textarea. 2017-11-28 12:53:40 -08:00
Tommy Ip 6a694418b2 refactor: s/error-msg/compose-error-msg. 2017-11-27 21:35:14 -08:00
Tommy Ip c0c58f9761 refactor: s/send-status/compose-send-status. 2017-11-27 21:35:14 -08:00
Tommy Ip ddaff4cd2a refactor: Extract upload mechanics to new JS module.
Tweaked by tabbott to move changes from the next commit that are
required for this to pass tests into this commit.

Note that this exports a few items that were not previously exported.
2017-11-27 21:31:51 -08:00
Tim Abbott 0445322625 compose: Export the major upload-related methods.
This is a preparatory commit to moving these to their own module.
2017-11-27 21:31:24 -08:00
Tim Abbott df58f0f7ae compose: Export some upload-related variables. 2017-11-27 21:31:23 -08:00
Steve Howell 025b8c19ae Simplify code to warn about private stream links.
This change does a few things:

    * I use "early return" to make the code a bit flatter
      and easier to comment.

    * I added more comments.

    * I removed some unneeded passing of `invite_only` into
      the template.
2017-11-27 10:41:10 -08:00
Rhea Parekh 1d826ae201 composebox: Warn when linked to private streams.
Fix issue #6860
2017-11-27 07:41:59 -08:00
Aastha Gupta c84f1686b7 emoji: Display emoji in messages as text as well as reactions.
Fixes #6795.
2017-11-15 16:59:11 -08:00
Umair Khan 597a6e6c74 user-groups: Add user groups in typeahead code. 2017-11-13 11:42:17 -08:00
Steve Howell 12dc567a89 Move insert_syntax_and_focus() to compose_ui.js.
This change also removes a couple lines of test code that
weren't really testing anything.
2017-11-09 09:49:20 -08:00
Jack Zhang fef828a037 compose: Add video link button, powered by Jitsi. 2017-10-30 17:13:47 -07:00
Steve Howell 2699a6aac9 refactor: Extract people.is_valid_email_for_compose().
It's easier to unit test logic inside of people.js than compose.js.

We allow users to compose emails to any of our cross-realm bots.
Someday we may tighten up which cross-realm bots are valid targets,
since it's not necessarily the case that those bots do anything
useful when you send them messages.
2017-10-26 09:45:08 -07:00
Tim Abbott 82b708b721 eslint: Add and enforce space-in-parens lint rule. 2017-10-06 12:36:59 -07:00
Vishnu Ks d8f8e29ff5 frontend: Show link to delete files in quota exceeded error. 2017-09-14 06:04:09 -07:00
Umair Khan d52760d2ef i18n: Don't span i18n strings on multiple lines.
If we use string concatenation to span i18n strings across multiple
lines then we end with such strings to be translated by the translators:

```
"This is the first line"\n + "This is the second line"
```
2017-09-06 07:01:43 -07:00
Tim Abbott eb4635804f compose: Fix previews of /me messages.
Previously, we didn't do anything special when previewing /me messages.

Fixes #2115.
2017-08-27 09:48:27 -07:00
Tim Abbott 0f1768d0d1 compose: Fix confusing variable name in preview code path.
This seems to be the root cause of the bug fixed in the last commit.
2017-08-27 09:34:06 -07:00
Tim Abbott eb6d736df3 compose: Fix local rendering of previews.
Apparently, local rendering of previews had broken sometime in the
last few months in a refactoring that resulted in us passing a string,
rather than an object, into markdown.js.
2017-08-27 09:33:52 -07:00
Steve Howell 3f06f28ad7 sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related
to the following things:

    * sending data to /json/report_send_time
    * restarting the event loop if events don't arrive on time

The code related to /json/report changes the following ways:

    * We track the state almost completely in the new
      send_messages.js module, with other modules just
      making one-line calls.

    * We no longer send "displayed" times to the servers, since
      we were kind of lying about them anyway.

    * We now explicitly track the state of each single sent
      message in its own object.

    * We now look up data related to the messages by local_id,
      instead of message_id.  The problem with message_id was
      that is was mutable.  Now we use local_id, and we extend
      the local_id concept to messages that don't get rendered
      client side.  We no longer need to react to the
      'message_id_changed' event to change our hash key.

    * The code used to live in many places:
        * various big chunks were scattered among compose.js,
          and those were all moved or reduced to one-line
          calls into the new module
        * echo.js continues to make basically one-line calls,
          but it no longer calls compose.report_as_received(),
          nor does it set the "start" time.
        * message_util.js used to report received events, but
          only when they finally got drawn in the home view;
          this code is gone now

The code related to restarting the event loop if events don't arrive
changes as follows:

    * The timer now gets set up from within
      send_messages.message_state.report_server_ack,
      where we can easily inspect the current state of the
      possibly-still-in-flight message.

    * The code to confirm that an event was received happens now
      in server_events.js, rather than later, so that we don't
      falsely blame the event loop  for a downstream bug.  (Plus
      it's easier to just do it one place.)

This change removes a fair amount of code from our node tests.  Some
of the removal is good stuff related to us completing killing off
unnecessary code.  Other removals are more expediency-driven, and
we should make another sweep at ramping up our coverage on compose.js,
with possibly a little more mocking of the new `send_messages` code
layer, since it's now abstracted better.

There is also some minor cleanup to echo.resend_message() in this
commit.

See #5968 for a detailed breakdown of the changes.
2017-08-01 08:58:56 -07:00
Steve Howell 90c5b53da3 Remove send_times_log feature.
We no longer use this in development.
2017-07-31 14:57:34 -07:00
Tim Abbott 6a50e13156 uploads: Remove legacy /json/upload_file endpoint.
This migrates Zulip to use the equivalent API endpoint that has been
present for a while.
2017-07-31 13:08:06 -07:00
Tim Abbott 4f4d28477d markdown: Rename markdown.contains_bugdown.
This name was confusing, since "bugdown" doesn't exactly suggest
"backend markdown processor" to people.
2017-07-28 17:51:33 -07:00
hollywoodno f7d1abaa25 compose.js: Prevent sending empty messages in preview mode.
This commit specifically addresses the issue when in preview mode,
while "enter sends" is enabled. Previously the messages were just
sent, now they must pass validation.

Fixes #5574.
2017-07-25 22:33:22 -04:00
Cory Lynch d32e89aae4 jQuery: Remove broken use of "removeAttr".
This function no longer sets properties to false, so the supported
way of doing this is to instead use prop(foo, false). Some tests
had to be fixed to accommodate this.
2017-07-24 10:54:47 -07:00
Steve Howell 0e25055c1d Add explicit message field for locally_echoed.
We now set locally_echoed to true for messages that are
locally echoed, and we change some of our code to look
for this flag.
2017-07-21 11:38:25 -07:00
Steve Howell 475eb21a5e Revert commits related to client_message_id.
I pushed a bunch of commits that attempted to introduce
the concept of `client_message_id` into our server, as
part of cleaning up our codepaths related to messages you
sent (both for the locally echoed case and for the host
case).

When we deployed this, we had some strange failures involving
double-echoed messages and issues advancing the pointer that appeared
related to #5779.  We didn't get to the bottom of exactly why the PR
caused havoc, but I decided there was a cleaner approach, anyway.
2017-07-14 12:13:35 -07:00
Steve Howell fe66d4f3b0 Encapsulate message_state.maybe_restart_event_loop().
We now set the timer for missing events inside the
message_state class, where it's easier for us to know
which state we're in.
2017-07-13 23:42:27 -04:00
Steve Howell bc67f6a8ca Add sent_messages.track_messages().
This change has us tracking messages as soon as we start
sending the message to the server.  The next step is to
reconfigure the timeouts a bit to deal with the server not
responding.
2017-07-13 23:42:27 -04:00
Steve Howell 9ee2be4a0d Use client_message_id as key for sent_messages lookups.
We now use a client-side message id to track the state of our
sent messages.  This sets up future commits to start tracking
state earlier in the message's life cycle.

It also avoids ugly reify logic where we capture an event to
update our data structure to key on the server's message id
instead of the local id.  That eliminates the node test as well.

Another node test gets deleted here, just because it's not
worth the trouble with upcoming refactorings.
2017-07-13 23:42:27 -04:00
Steve Howell 7e88fb25b3 Move sent_messages callbacks into transmit_message().
This mostly sets the stage for a subsequent commit to start
using client_message_id as the key into sent_messages.

It has the nice side effect of making it more explicit that
certain things should always happen when transmit_message()
succeeds.

This commit does regress our node test coverage a bit.
2017-07-13 23:42:27 -04:00
Steve Howell 68f8ba0449 Generate client_message_id() sequentially.
This commit starts to decouple client_message_id from local_id.

We don't really take advantage of the decoupling in this
commit--in fact, it's a bit of a pain at first.  But this should
be a fully working checkpoint commit.
2017-07-13 23:42:27 -04:00
Steve Howell f6d670ae3d Extract sent_messages.js.
This is mostly straightforward moving of code out of compose.js.

The code that was moved currently supports sending time
reports for sent messages, but we intend to grow out the new
module to track more state about sent messages.

The following function names in this commit are new, but their
code was basically pulled over verbatim:

    process_success (was process_send_time)
    set_timer_for_restarting_event_loop
    clear
    initialize

All the code in the new module is covered by previous tests that
had been written for compose.js.  This commit only modifies
a few things to keep those tests.

The new module has 100% node coverage, so we updated `enforce_fully_covered`.
2017-07-13 23:42:27 -04:00
Steve Howell 8fbb55df85 Introduce client_message_id on the server.
We are deprecating local_id/local_message_id on the Python server.
Instead of the server knowing about the client's implementation of
local id, with the message id = 9999.01 scheme, we just send the
server an opaque id to send back to us.

This commit changes the name from local_id -> client_message_id,
but it doesn't change the actual values passed yet.

The goal for client_key in future commits will be to:
    * Have it for all messages, not just locally rendered messages
    * Not have it overlap with server-side message ids.

The history behind local_id having numbers like 9999.01 is that
they are actually interim message ids and the numerical value is
used for rendering the message list when we do client-side rendering.
2017-07-13 23:42:27 -04:00
Aditya Bansal 2342a8f0e4 compose.js: Remove dead code from get_invalid_recipient_emails().
The piece of code is dead since there can be no instance where
email === ''. This is ensured by util.extract_pm_recipients
by filtering for empty strings in the pm_recipients list.
2017-07-11 12:14:09 -04:00
Aditya Bansal 93a003749e compose.js: Remove dead code from mark_end_to_end_display_time().
This piece was dead because exports.send_times_data[message_id]
cannot be undefined since the only place this function is called
from is exports.report_as_received() and that function has a call
to mark_end_to_end_receive_time() before a call is made to the
function in question for dead code. The function call to
mark_end_to_end_receive_time results in
exports.send_times_data[message_id] = {} if this was not defined
already. So there can be no instance where we end up the code
being removed.
2017-07-11 12:14:09 -04:00
Aditya Bansal 237ec76bdc compose.js: Remove broken test_send_many_messages(). 2017-07-11 12:14:09 -04:00
Steve Howell 1cf18cfbeb compose: Avoid render for duplicate mentions.
There is no reason to render the template for compose mention
warnings if the user is already in the widget.

This commit also restructures the unit test significantly to more
carefully exercise each case, particularly in regard to when
templates get rendered.
2017-07-09 08:30:46 -04:00
Aditya Bansal 05a21b3729 compose.js: Fix Jquery selector to use more prominent syntax. 2017-07-09 07:26:09 -04:00
Aditya Bansal c7ec7f98d9 compose.js: Use on() instead of deprecated bind(). 2017-07-07 07:50:02 -04:00
Aditya Bansal 2b14714e3b compose.js: Export send_message().
We do this in order to have the definition of send_message()
accessible to the outside world. This will help in testing
this function.
2017-07-06 17:44:27 -04:00
Aditya Bansal 28ec32d757 compose.js: Use get_subscriber_count in show_all_everyone_warning(). 2017-06-30 19:57:14 +05:30
Aditya Bansal 2be5046144 compose.js: Use stream_data.get_subscriber_count in message mentions.
In this commit we basically start using the get_subscriber_count
function from stream data to get subscriber count.
2017-06-29 10:34:47 -04:00
Aditya Bansal 7a0387e0b1 compose.js: Add return true for subscribed streams.
This is basically going to fix a regression which was introduced in
89090cd which made code early return in case of subscribed streams.
2017-06-29 18:02:25 +05:30
Aditya Bansal 84b52661bb compose.js: Remove small piece of dead code.
In this commit we remove a small piece of dead code from
check_stream_for_send() function and also rename it to
check_unsubscribed_stream_for_send() which makes more sense.
2017-06-28 07:45:21 -04:00
Aditya Bansal 89090cd3af compose.js: Refactor validate_stream_message_address_info().
In this commit we just refactor validate_stream_message_address_info
function to early return in case of stream_data.is_subscribed()
returns true.
2017-06-28 07:45:21 -04:00
Aditya Bansal eec9a9babb compose.js: Export validate_stream_message_address_info(). 2017-06-28 07:45:21 -04:00
Aditya Bansal 411883365a compose.js: Create initialize() function. 2017-06-26 15:55:10 -04:00
Harshit Bansal 6615f2f2e8 common.js: Migrate `common.js` module to use IIFE module style.
This module was exposing its functions as globals. This PR fixes
it use the IIFE module style that we use in our other modules.
2017-06-22 19:06:32 -04:00
Tejas Kasetty 4487899099 file-attach: Reset file_input after each trigger.
The file input used for attaching files and images was not being reset
after each use. This resulted in irregular behaviour (sometimes failure)
in attaching the same file consecutively.
This fixes the bug in the reset method.

Fixes #5074.
2017-06-08 19:53:31 -07:00
Steve Howell 94b7058743 Make local_echo an official feature.
This commit removes all references to feature_flags.local_echo.
It's been a core feature for about four years, so I think we
can safely say the experiment was successful.:)
2017-05-09 11:06:10 -07:00
Steve Howell 0a0f567aeb Split out markdown.js from echo.js.
The new module handles markdown rendering.

The code left behind in echo.js does local-echo kind of things
like reifying message ids.
2017-05-09 11:06:10 -07:00
Mahim Goyal 6464514ca9 Break compose.js and drafts.js dependency. 2017-05-08 14:43:49 -07:00
fionabunny 7db8c61aac home.py: move event_queue_id as queue_id to register_ret.
Simplify the page_params generation logic #3853
2017-04-28 21:33:17 -07:00
fionabunny 70fe2eab60 home.py: move is_zephyr_mirror_realm as realm_is_zephyr_mirror_realm.
Part of #3853.
2017-04-28 21:12:16 -07:00
fionabunny 64041e0da1 home.py: move mandatory_topics as realm_mandatory_topics to register_ret.
Part of #3853.
2017-04-28 21:12:05 -07:00
Rafid Aslam 7b2ef7c1a9 compose: Validate subscriptions in browser when !autosubscribe.
This doesn't quite complete the goals of #4650, which has a plan for
how to remove this entirely, but it causes this problematic code to
now be contained to a very rare case.

Refactored significantly by tabbott just due to rebase age.

Fixes #3629.
2017-04-28 17:46:15 -07:00
Tim Abbott 3f1df50c7b compose: Remove unnecessary check_stream_existence wrapper.
This function had become just an empty shell.
2017-04-28 17:41:12 -07:00
Tim Abbott e0954d8811 compose: Refactor check_stream_for_send error handling.
The extra lines in removed were already part of compose_error.
2017-04-28 17:41:02 -07:00
Steve Howell 5965dc092a Move check_stream_existence() to compose.js.
The function check_stream_existence() temporarliy got moved
to stream_create.js, and our call from compose.js was still trying
to find it in subs.js.  Now we move the function to compose.js,
since we no longer use it stream_create.js.

This function is pretty dubious, and we may want to only check
for duplicate stream names locally.
2017-04-28 16:17:52 -07:00
Cory Lynch f9d1bff167 Fix textarea resize for editing messages.
Reusing code from the main compose_message component so that resizing now
behaves correctly. This means that when the user tries to resize vertically,
the autoresize code is disabled, and the textbox reverts to manual resizing.
Fixes #4573
2017-04-28 12:15:34 -07:00
Steve Howell 7326971380 Extract stream_edit.js.
This code makes the right pane work in "Manage Streams" when
you are editing a stream subscription.  It handles basic
functionality (submitting forms, etc.), live updates, and
showing the pane as needed.

Most of the code here was simply moved from subs.js, but some
functions were pulled out of larger functions:

    live update:
        add_me_to_member_list
        update_stream_name
        update_stream_description

    collapse/show:
        collapse
        show_sub

We also now export subs.show_subs_pane.

We eventually want stream_edit not to call into subs.js, and
this should be fairly easy--we just need to move some shared
methods to a new module.
2017-04-25 09:57:32 -07:00
Steve Howell c999bdf823 compose: Distinguish get_message_type() from composing().
We now only call compose_state.composing() in a boolean context,
where we simply care whether or not the compose box is open.  The
function now also returns true/false.

Callers who need to know the actual message type (e.g. "stream" or
"private") now call compose_state.get_message_type().
2017-04-24 12:42:06 -07:00
Steve Howell 70b7d4c00b Extract compose_state.js.
This is mostly just moving methods out of compose.js.

The variable `is_composing_message`, which isn't a boolean, has
been renamed to `message_type`, and there are new functions
set_message_type() and get_message_type() that wrap it.

This commit removes some shims related to the global variable
`compose_state`; now, `compose_state` is a typical global
variable with a 1:1 relationship with the module by the same
name.

The new module has 100% line coverage, most of it coming
via the tests on compose_actions.js.  (The methods here are
super simple, so it's a good thing that the tests are somewhat
integrated with a higher layer.)
2017-04-18 12:26:58 -07:00
Benjamin Gilbert 4775f55ca7 Fix spelling of "occurred" in various places. 2017-04-17 20:29:07 -07:00
Yago González e710110a9e i18n: Automatically strip Handlebars strings.
Some Handlebars strings contained whitespaces characters at their ends.
With this, such characters are removed, as well as multiple spaces
(like the ones produced by code indentation).

This also includes a couple of fixes that removes spaces that were
intentionally placed before/after the string to translate.
2017-04-14 17:37:25 -07:00
Steve Howell 5ba79f9c3a refactor: Move respond/reply methods to compose_actions.js.
This moves respond_to_mention() and reply_with_mention() to
compose_actions.js.  These methods are basically thin layers
on top of compose_actions.start().
2017-04-14 13:09:19 -07:00
Steve Howell dd0c50f0df Extract compose_actions.js.
This module extracts these two functions that get called by
several other modules:

    start()
    cancel()

It is a little bit arbitrary which functions got pulled over
with them, but it's generally functions that would have only
been called via start/cancel.

There are two goals for splitting out this code.  The first
goal is simply to make `compose.js` have fewer responsibilities.
The second goal is to help break up circular dependencies.
The extraction of this module does more to clarify
dependencies than actually break them.  The methods start()
and cancel() had actually been shimmed in an earlier commit,
and now they no longer have a shim.

Besides start/cancel, most of the functions here are only
exported to facilitate test stubbing.  An exception is
decorate_stream_bar(), which is currently called from
ui_init.js.  We probably should move the "blur" handler out
of there, but cleaning up ui_init.js is a project for another
day.

It may seem slightly odd that this commit doesn't pull over
finish() into this module, but finish() would bring in the
whole send-message codepath.  You can think of it like this:

* compose_actions basically just populates the compose box
* compose.finish() makes the compose box do its real job,
  which is to send a message
2017-04-14 13:09:19 -07:00
Steve Howell 703074215a Export compose.abort_xhr(). 2017-04-14 13:09:19 -07:00
Steve Howell 254b9559da Export compose.clear_preview_area(). 2017-04-14 13:09:19 -07:00
Steve Howell 9bd096f3cf compose: Extract blur_textarea(). 2017-04-14 13:09:19 -07:00
Steve Howell ec8bd077d1 compose: Extract clear_textarea(). 2017-04-14 13:09:19 -07:00
Steve Howell e23b660ccc compose: Extract set_focus().
Most of the code here was in show_box(), but we also pull in the
call to get_focus_area() from compose.start().
2017-04-13 17:13:19 -07:00
Steve Howell 0841320966 compose: Extract maybe_scroll_up_selected_message().
The extraction here is straightforward, but where we put the
caller is a slightly subtle change.  Instead of continuing to
invoke this code at the end of show_box(), we instead call it
at the beginning of complete_starting_tasks().  This change is
valid, because show_box() and complete_starting_tasks() are only
ever called from compose.start().
2017-04-13 17:13:19 -07:00
Steve Howell aa5409cf3a compose: Extract complete_starting_tasks(). 2017-04-13 17:13:19 -07:00
Steve Howell e73b56c7b5 compose: Extract expand_compose_box(). 2017-04-13 17:13:19 -07:00
Steve Howell 79ff32a01e compose: Extract autosize_message_content(). 2017-04-13 17:13:19 -07:00
Sampriti Panda 32e76c2c60 drafts: Move snapshot_message from compose to drafts
Previously drafts called compose.snapshot_message which would then
get the message object from compose.create_message_object. This method often
checked for the validity of stream/user recipients which would often cause tracebacks.

The new method in drafts.snapshot message just gets the data from the fields and
stores them in the draft model without any additional checking.
2017-03-30 10:20:37 -07:00
Tim Abbott ccb38a1e9c compose: Fix missing opts argument to show_box.
This fixes a regression in the recent compose.get_focus_area
refactoring that I did.
2017-03-22 16:32:53 -07:00
Steve Howell 1ec392a18e Extract compose.get_invalid_recipient_emails(). 2017-03-22 07:01:20 -07:00
Tim Abbott 8b9e78e486 compose: Extract and test get_focus_area. 2017-03-21 17:24:40 -07:00
Tim Abbott 82ec083066 compose: Fix new topic button behavior in home view. 2017-03-21 17:24:40 -07:00
Steve Howell d026344b37 Extract js/ui_util.js. 2017-03-19 11:05:45 -07:00
Steve Howell 16a37754cf Add recipient() and composing() shims. 2017-03-18 15:52:50 -07:00
Steve Howell faa9446e64 Add compose_actions.start() shim. 2017-03-18 15:52:50 -07:00
Steve Howell 35d38d62f3 Add shim.js w/narrow_state global. 2017-03-18 15:52:50 -07:00
Steve Howell a51caceea5 refactor: Extract unread_ops.js
This module mostly contains the mark_* functions that
update the server with info about unread counts.
2017-03-18 10:35:52 -07:00
Tim Abbott 8efe4d530d js: check_stream_existence to subs.js.
We want to remove this, but in the meantime, this is a more coherent
place for htis to live than compose.js.
2017-03-17 15:16:11 -07:00
Brock Whittaker c155577246 Allow users to resize the message compose box.
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.
2017-03-14 17:40:21 -07:00
Steve Howell 87a7313143 refactor: Extract compose.reply_with_mention(). 2017-03-13 15:09:53 -07:00
Tim Abbott 5e39ccd642 js: Rename viewport.js to message_viewport.js.
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.
2017-03-10 14:59:59 -08:00
Tim Abbott 3b59e6c3cc subs: Rename /#subscriptions to /#streams.
Fixes #3653.
2017-03-08 16:57:58 -08:00
Raghav Jajodia 21f0339cfc compose: Focus on topic when narrowed to a stream+topic.
When narrowed to a stream+topic and clicking the "new topic" button,
focus in on topic and the text remains selected.
Fixes #3888.
2017-03-07 22:24:57 -08:00
Steve Howell 190b2ab1d3 refactor: Pass in a sub to invite_users_to_stream(). 2017-03-05 11:55:09 -08:00
Steve Howell 8a4dee4a80 bug fix: Handle bad streams for compose-invite feature.
We now handle missing subs more gracefully when you click on the
link to invite somebody you at-mentioned in a stream message.
2017-03-05 11:55:09 -08:00
Steve Howell 434f228135 refactor: Avoid nesting in the compose invite handler.
We exit early now if email is undefined, rather than
having a big if statement.
2017-03-05 11:55:09 -08:00
Philip Skomorokhov 866a7b06b2 upload: Limit total size of files uploaded by a user to 1GB.
Fixes #3884.
2017-03-04 18:08:30 -08:00
Tim Abbott 7fb406b889 lint: Expand lint check for use of .text() without i18n.
Fixes #3705.
2017-02-28 20:37:52 -08:00
Steve Howell df2abf0529 Populate message.to_user_ids in compose.js. 2017-02-26 16:18:02 -08:00
Steve Howell 49496cee58 Remove message param from compose.snapshot_message(). 2017-02-26 16:18:02 -08:00
Steve Howell 9c63e055e2 Simplify create_message_object() for PM fields.
We now only populate PM fields if the message type is
private, and we make only one call to compose.recipient().
2017-02-26 16:18:02 -08:00
Steve Howell 49ab8035f8 Populate stream_id when composing messages. 2017-02-26 16:18:02 -08:00
Sampriti Panda 1929cc5190 Implement persistent drafts functionality
* 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.
2017-02-23 02:58:23 -08:00
Tim Abbott e608f09f73 compose: Remove unnecessary snapshot_message call.
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.
2017-02-21 19:24:38 -08:00
Tim Abbott e29663a2b3 compose: Fix behavior hitting enter with the preview area open.
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.
2017-02-18 23:31:54 -08:00
Tim Abbott f105e8270d compose: Fix hardcoding of 'website' client.
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.
2017-02-17 15:20:32 -08:00
Tim Abbott 9072d3c350 socket: Transmit HTTP_USER_AGENT for websockets sending.
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.
2017-02-17 15:19:21 -08:00
Tim Abbott 5c34c601d9 compose: Trim trailing whitespace in messages.
This should ensure that local echo matches the backend in handling of
unusual input like `/me `.
2017-02-11 23:01:22 -08:00
Elliott Jin 4092aab620 unread: Refactor to move DOM element updates into UI layer. 2017-02-11 08:36:39 -08:00
Steve Howell 2e07533b4e Add compose.update_email().
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.
2017-02-10 21:57:50 -08:00
Steve Howell f8d59c8108 Make compose replies for PMs more robust.
We now use user_ids from the message to generate the
reply_to more dynamically.
2017-02-10 21:57:50 -08:00
kpdp cda7faee83 compose: Fix the compose box not resizing when restoring drafts.
Fixes #3592.
2017-02-07 14:41:44 -08:00
khantaalaman 8c7321abad compose: Show restore-draft option in write mode only.
Fixes #3491.
2017-02-02 11:42:56 -08:00
Eitan Adler 0ce29d7ad6 Remove some some duplicate words in copy. 2017-01-23 23:15:04 -08:00
Sampriti Panda 196cf4367b urls: Move /messages/render to POST endpoint 2017-01-13 16:11:51 -08:00
Tim Abbott 998dff9e50 lint: Add dangling commas in JavaScript objects. 2017-01-11 15:23:42 -08:00
Sampriti Panda 45a5e47e1b compose: Fix bug on sending message to invalid streams.
The issue is that we were trying to validate the mentions before
checking that the recipient stream was valid, leading to problems
checking the membership of the stream.

Fixes #3040.
2017-01-05 15:26:54 -08:00
Sampriti Panda c15d1ff343 compose: Split validate_stream_message into separate functions. 2017-01-05 15:26:03 -08:00
Tim Abbott e943c1d247 compose: Export autosize_textarea. 2017-01-03 19:14:38 -08:00
Arpith Siromoney 5639f21188 Add missing exports to js modules 2016-12-29 06:01:33 -08:00
Tim Abbott 5ad9a9d014 compose: Fix websockets having been accidentally disabled.
When we renamed use_socket to use_websockets, we only renamed it on
the backend, and thus it became effectively hardcoded to false.
2016-12-28 09:24:19 -08:00
Sanskar Modi e6beaa2711 Improve @all warnings user interface significantly.
* Doesn't pop up the warning until you actually try to send the message
* Eliminates the red warning.
* Changes confirm text to "Yes, send".
* Adds a stream size threshhold of 15 people; smaller streams don't
  prompt about this.

Fixes #2257.
2016-12-21 11:40:47 -08:00
Tim Abbott f0f4be4af7 lint: Fix remaining no-unused-vars eslint rule violations. 2016-12-14 22:36:47 -08:00
Rafid Aslam 45f39be37f lint: Fix many no-unused-vars eslint rule violations.
These have been carefully audited by tabbott to ensure they are
unlikely to cause regressions.
2016-12-14 21:34:51 -08:00
Zac Pullar-Strecker e6e11aefb3 settings: Add option to disable websockets.
This can be useful in scenarios where the network doesn't support
websockets.  We don't include it in prod_settings_template.py since
it's a very rare setting to need.

Fixes #1528.
2016-12-05 21:55:22 -08:00
lonerz dc6849952b eslint: change space-before-function-paren from warning to error.
Also fix violations.
2016-12-05 09:50:37 -08:00
AZtheAsian 5e9918135b eslint: change quote-props from off to error and fix violations. 2016-12-02 18:35:53 -08:00
AZtheAsian 9c0ebc7359 eslint: change no-else-return to error and fix violations 2016-12-02 14:43:09 -08:00
AZtheAsian ed0bc831be eslint: change one-var from warning to error and fix violations 2016-12-02 11:25:16 -07:00
Tommy Ip b3f4feb996 eslint: change max-len from warning to error and fix violations. 2016-12-02 14:16:33 +00:00
Tommy Ip c90da24541 eslint: change keyword-spacing from warning to error and fix violations. 2016-12-01 14:22:15 -08:00
Steve Howell 9b04ec7472 Send dicts for cross realm users to JS.
We now send dictionaries for cross-realm bots.  This led to the
following changes:

* Create get_cross_realm_dicts() in actions.py.
* Rename the page_params field to cross_realm_bots.
* Fix some back end tests.
* Add cross_realm_dict to people.js.
* Call people.add for cross-realm bots (if they are not already part of the realm).
* Remove hack to add in feedback@zulip.com on the client side.
* Add people.is_cross_realm_email() and use it in compose.js.
* Remove util.string_in_list_case_insensitive().
2016-11-03 09:51:23 -07:00
deekshaarul 05d252da71 compose.js: Add translation tag to empty_topic_placeholder.
Moves the variable definition from the top of the file to inside the export
since i18n seems not be loaded at the time the file is parsed.
2016-11-02 17:46:32 -07:00
hackerkid 9a2e24a458 Use spinner as message preview loader. 2016-09-26 21:00:28 -07:00
hackerkid dc355fcf1e Use backend markdown processor in message preview.
[tweaked by tabbott to add comment and fetch the authoritative
rendering from the backend unconditionally]

Fixes #1834.
2016-09-25 22:17:40 -07:00
hackerkid 0412e1e20b Add support for markdown preview in compose area.
This doesn't currently use the backend markdown processor, so the
previews are not completely faithful.

Fixes #217.
2016-09-21 22:33:35 -07:00