Commit graph

2910 commits

Author SHA1 Message Date
Michael James Gratton
53caf43fca Replace ad-hoc ComposerWebView cursor signal param w/ structured object.
This lets us notify of more cursor editing context state in the future
without changing the signal signature.

* src/client/composer/composer-web-view.vala (ComposerWebView): Replace
  cursor_style_changed signal and cursorStyleChanged JS message with
  cursor_context_changed signal and cursorContextChanged message, add new
  EditContext inner class and pass as arg to new signal, update call
  sites. Move parsing of JS message to new inner class. Add unit tests,
  fix a font-family bug revealed by tests.

* ui/composer-web-view.js (ComposerPageState): Replace cursorFontFamily
  and cursorFontSize with a cursor context and new EditContext object to
  encapsulate them, update them from a node and serialise them. Add unit
  tests.
2017-02-01 00:41:44 +11:00
Michael James Gratton
617dd45393 Remove use of underscores in client-web-view.js var names. 2017-02-01 00:41:44 +11:00
Michael James Gratton
4e9104a79b Convert ComposerWidget destroy handler back to an overridden method. 2017-02-01 00:41:44 +11:00
Michael James Gratton
ceb6400e1c Ensure composer selection actions are not enabled when first opened.
* src/client/composer/composer-widget.vala (ComposerWidget): Rename
  on_selection_changed to update_selection_actions, call as needed. Tidy
  action init methods a bit.

* src/client/components/client-web-view.vala (ClientWebView): Add new
  has_selection property and keep it updated.
2017-02-01 00:41:44 +11:00
Michael James Gratton
f27dea1318 Update some composer action tooltips. 2017-02-01 00:41:44 +11:00
Michael James Gratton
b1d4eaa32f Implement milliseconds ctor and tests for Geary.TimeoutManager. 2017-02-01 00:41:44 +11:00
Michael James Gratton
b20b3cafad Update composer's draft manager lifecycle management.
* src/client/composer/composer-widget.vala
  (ComposerWidget::initialize_actions): Disable close-and-save by
  default, opening draft manager will enable it if needed.
  (ComposerWidget::restore_draft_state_async): Update doc comment noting
  use constraints, remove account param since we should be using the
  instance's instead. Update call site.
  (ComposerWidget::open_draft_manager_async): Don't try to close the
  manager beforehand, we should be able to manage that externally.
  (ComposerWidget::reopen_draft_manager_async): New async method to
  handle closing and reopening the draft manager in the appropriate
  order, since it's one caller is not async.
  (ComposerWidget::discard_and_exit_async): Only attempt to discard the
  draft if we have a draft manager. We need the guard since this may also
  get called even if drafts are not being saved.
  (ComposerWidget::set_header_recipients): Don't flag draft as having
  changed, these issues should only be cosmetic.
  (ComposerWidget::on_from_changed): Move to a more appropriate location
  in the source, just call ::reopen_draft_manager_async instead of trying
  to handle it here.
2017-02-01 00:41:44 +11:00
Michael James Gratton
f8957c4d7a Ensure draft is saved when envelope (from, to, etc) changes. Bug 726290.
* src/client/composer/composer-widget.vala (ComposerWidget): Rename
  subject changed handler to something more generic, hook that up to the
  to/cc/bcc & reply_to entries.

* ui/composer-widget.ui: Hook up multiple to on_envelope_changed, make
  subject entry use that as well.
2017-02-01 00:41:44 +11:00
Michael James Gratton
836efc926e Tidy up ComposerWidget::should_close().
* src/client/composer/composer-widget.vala (ComposerWidget): Add
  `can_save` property that defined what the composer's reqwuirements for
  being able to save a draft.
  (ComposerWidget::should_close): Use can_save rather than should_save to
  determine which confirmation dialog to show. When keeping, only save if
  we need to. Split up handling responses from 2 and 3 button dialogs so
  it's more clear what is going on in each case.
2017-02-01 00:41:44 +11:00
Michael James Gratton
034727cc04 Minor draft-related code cleanup. 2017-02-01 00:41:44 +11:00
Michael James Gratton
f4b7e69545 Only save a new draft if the current draft has not been saved.
* src/client/composer/composer-widget.vala (ComposerWidget): Add
  ::is_draft_saved field, update it as the draft manager's state changes,
  or if the message has been changed. Rename ::can_save to ::should_save
  to better reflect what it is used for, don't allow saving if a draft
  has been saved. Rename update_draft_state as a proper method, use it
  update initial state after opening draft manager, tidy up location of
  draft signal handlers.
2017-02-01 00:41:44 +11:00
Michael James Gratton
58b76ba958 Close the composer if the message is blank. Bug 743970. 2017-02-01 00:41:44 +11:00
Michael James Gratton
840a76dac3 Cleanup code, registration and memory management for JS message handlers.
* src/client/components/client-web-view.vala (ClientWebView): Introduce
  new JavaScriptMessageHandler delegate for JS message handler callbacks.
  (ClientWebView::register_message_handler): Add delegate as second param
  and register it as the callback for the handler. Update call sites to
  use this form, do not have them explicitly unref the JavascriptResult
  since WK2 is doing the right thing, and clean them up in general.
2017-02-01 00:41:44 +11:00
Michael James Gratton
58588aa580 Re-enable inserting inline images in the composer.
* src/client/components/client-web-view.vala (ClientWebView): Remove
  now-unsed ;;allow_prefix property. Add ::insert_image method.

* src/client/composer/composer-widget.vala (ComposerWidget): Split up
  "attachment" handling into inline and attached parts so we can require
  a Content ID be passed in for inline parts. Convert ::inline_files set
  into a map, so we can be explict about the IMG SRC URL that was used to
  refer to the inline part, either cid or geary, and update call sites.
  (ComposerWidget::on_insert_image): Simply add the image as a new inline
  part with a geary URL, and insert it via the editor.

* src/engine/api/geary-composed-email.vala (ComposedEmail): Also use a
  map of inline parts, for the same reason as ComposerWidget. Update call
  sites.

* src/engine/rfc822/rfc822-message.vala (Message.from_composed_email):
  Use the given URL for inline parts when assigning Content IDs and
  replacing the internal URL in the source.
2017-02-01 00:41:44 +11:00
Michael James Gratton
70cbe4a046 Allow ClientWebView resources to be loaded via either cid or geary URLs.
* src/client/components/client-web-view.vala (ClientWebView): Rename
  members referring to inline resources to internal resources, update
  call sites.
  (ClientWebView::handle_cid_request,
   ClientWebView::handle_internal_request): Rework to use new common
   ::handle_internal_response method.

* src/client/web-process/web-process-extension.vala: Permit by default
  any geary, cid, or data URI request.
2017-02-01 00:41:44 +11:00
Michael James Gratton
d5545abfb5 Fix not being able to save some inline images.
* src/client/conversation-viewer/conversation-message.vala
  (ConversationMessage::on_resource_load_started): Always store loaded
  resources for saving, not only if they have internal URLs.
2017-02-01 00:41:44 +11:00
Michael James Gratton
d2bc005d62 Don't run slow timer tests unless specifically requested. 2017-02-01 00:41:44 +11:00
Michael James Gratton
a6262a14d2 Minor TimeoutManager optimisation. 2017-02-01 00:41:44 +11:00
Michael James Gratton
fcf5be297e Re-enable composer empty body checking and draft save timer.
* src/client/composer/composer-web-view.vala (ClientWebView): Add a
  ::document_modified signal and a documentModified JS message listener,
  fire it when the JS message is receieved. Update value of ::is_empty
  based on whether a non-empty HTML body was provided in the first place,
  and if it has been subsequently modified. Update related doc comments a
  bit.

* src/client/composer/composer-widget.vala (ComposerWidget): Rename
  `blank` property to `is_blank`, fix sense of editor.is_blank check,
  update call sites. Convert ::can_save method into a property, include
  the this.is_blank check since there's no point saving a blank message,
  updtae call sites. Replace use of GLib.Timeout with
  Geary.TimeoutManager, tidy up resulting code, hook up timer to new
  document_modified signal.

* ui/composer-web-view.js: Use body mutation observer to send
  documentModified messages to the client, coalescing consecutive events
  over a period of 1s into a single message.
2017-02-01 00:41:44 +11:00
Michael James Gratton
8d479cf437 Fix one actual and one possible async race saving drafts.
* src/client/composer/composer-widget.vala (ComposerWidget::save_draft):
  Make this method async, so we can yield when calling
  ::get_composed_email instead of starting it with begin(). This means
  that in ::save_and_exit_async, we can in turn yield to ::save_draft, to
  ensure the message is saved before closing the draft manager.
  (ComposerWidget::on_from_changed): Don't blindly reset the draft timer
  after starting to open the draft manager, it will fail if opening the
  draft manager takes longer than the timer. Instead, reset the timer in
  an async callback.
2017-02-01 00:41:44 +11:00
Michael James Gratton
1572afc5ed Update composer hover url and link overlay correctly on mouseover/out. 2017-02-01 00:41:44 +11:00
Michael James Gratton
8e58a67a00 Fix up new composers not getting correct focus.
* src/client/application/geary-controller.vala
  (GearyController::create_compose_widget_async): Explictly set the focus
  once the composer has been added to the widget hierarchy.
2017-02-01 00:41:44 +11:00
Michael James Gratton
a8d1da7ee7 Fix infinite WebView key event chain when it doesn't handle a key press.
* src/client/components/main-window.vala (MainWindow): Convert
  on_key_press_event handler to override Gtk.Window's key_press_event
  virtual method. Reimplement that so that single keystroke shortcuts
  work, but also so GtkWindow.propagate_key_event only gets called once,
  and the WebKit event loop is avoided. See source comments for
  details. Also clean up shift up/down handling to not update when any
  GtkEntry or ComposerWebView is focused.
2017-02-01 00:41:44 +11:00
Michael James Gratton
a498719723 Clean up compser key event handling.
* src/client/composer/composer-web-view.vala (ComposerWebView:): Rmeove
  is_shift_down property and key handling that updates it. We aren't
  gonna need it.

* src/client/composer/composer-widget.vala (ComposerWidget): Split out
  Ctrl+Return check for sending into a seperate method, so the editor key
  press handler doesn't end up calling ComposerWidget's parent's
  key_press_event implementation. Use Gdk.EVENT_FOO constants.
2017-02-01 00:41:44 +11:00
Michael James Gratton
fd97ad2887 Reimplement inserting/removing \t chars in the composer.
* ui/composer-web-view.js (ComposerPageState): Add tabOut/tabIn
  functions, listen to key Tab key pressess on the body and invoke the
  appropriate method if found.

* src/client/web-process/util-composer.vala: Removed old vala
  implementation of same.
2017-02-01 00:41:44 +11:00
Michael James Gratton
742573c978 Don't fail when G_DEBUG=fatal-warnings is set by default.
* src/client/components/client-web-view.vala
  (ClientWebView::load_user_stylesheet): Don't warn when we can't load
  the user CSS file, since that's likely to be the case.
2017-02-01 00:41:44 +11:00
Michael James Gratton
d7b9884c90 Fix attachments being added to the conversation email view many times.
* src/client/components/client-web-view.vala (ClientWebView::has_valid_height),
  src/client/conversation-viewer/conversation-email.vala
  (ConversationEmail::message_bodies_loaded): Only update the values of
  these properties when they have actually changed, to avoid sending
  multiple notifies out for them.
2017-02-01 00:41:44 +11:00
Michael James Gratton
28fe2a482f Minor code cleanup. 2017-02-01 00:41:44 +11:00
Michael James Gratton
67d81c3e15 Re-implement composer font family/size action state updating.
* src/client/composer/composer-web-view.vala (ComposerWebView): Add new
  ::cursor_style_changed signal, hook it up to the JS cursorStyleChanged
  message and interpret the raw results from the web view before passing
  it on.

* src/client/composer/composer-widget.vala (ComposerWidget): Replace
  remainder of old ::update_actions method with a listener for
  ComposerWebView::cursor_style_changed. Reimplement in terms of that
  signal.

* ui/composer-web-view.js: Keep track of font family and size changes,
  send a cursorStyleChanged message when they change.
2017-02-01 00:41:44 +11:00
Michael James Gratton
2bd5306d30 Reenable undo/redo composer actions.
* src/client/composer/composer-web-view.vala (ComposerWebView): Add new
  ::command_stack_changed signal to manage undo/redo enabled state, hook
  it up to a JS callback. Add ::is_empty property as a non-functioning
  shim in lieu of can_undo going away. Remove ::can_undo and ::can_redo,
  replace them with methods to actually fire an undo and redo.

* src/client/composer/composer-widget.vala (ComposerWidget): Use
  ClientWebView::is_empty rather inplace of can_redo for determining
  editing state. Remove old undo/redo signal hookups, replace with
  ::command_stack_changed and manage action enable state from there.
  (ComposerWidget::action_entries): Add explicit actions for undo/redo,
  since they need some custom code over on on the web process side.
  (ComposerWidget::on_compose_as_html_toggled): Explciitly manage the
  visibility of rich text toolbar buttons, don't rely on obscure
  GtkBuilder magic that Glade doesn't support.

* ui/composer-web-view.js: Add a mutation observer for the message body
  and explcit methods for firing undo/redo commands, so we can keep track
  of how the command stack changes. As it does, fire commandStackChanged
  messages back to the client process. Explicity set the message body as
  content-editable after the document has been mutated for quotes, etc.

* ui/composer-widget.ui: Add bonus undo/redo toobar buttons for the
  composer.
2017-02-01 00:41:44 +11:00
Michael James Gratton
b1d721dac6 Update and mostly reenable composer clipboard actions.
* src/client/components/client-web-view.vala (copy_clipboard): Fixed to
  actually copy, not cut. Removed can_copy_clipboard since it's no longer
  implementable or useful.

* src/client/composer/composer-web-view.vala (ComposerWebView): Remove
  can_cut_clipboard and can_paste_clipboard, since they are no longer
  implementable or useful. Implement simple part of insert_text so
  pasting plain text works, but still need to handle scroll update.

* src/client/composer/composer-widget.vala (ComposerWidget): Fix keyboard
  shortcut for copying. Remove old WK1 clipboard related events. Update
  clipboard actions' state using selection changed signal. Handle pasting
  plain and rich text via the editor.

* src/client/web-process/util-composer.vala (insert_clipboard_text):
  Remove code moved back to ComposerWebView.
2017-02-01 00:41:44 +11:00
Michael James Gratton
850730a69d Reimplement inserting additional replies into the composer. 2017-02-01 00:41:44 +11:00
Michael James Gratton
20db6e57dd Re-enable custom composer context menu, add WK text entry items to it.
* src/client/composer/composer-widget.vala
  (ComposerWidget::action_entries): Add an entry for the inspector so it
  can be loaded via the context model in the same way as other items.
  (ComposerWidget::context_menu_*): Keep track of a number of the context
  menu's sections, so we can selectively include them in the WK context
  menu.
  (ComposerWidget::on_context_menu): Re-implement to work wth the WK2
  context menu model, which annoyingly doesn't even extend any of the
  GtkMenu infrastrcuture.

* src/client/util/util-gtk.vala (menu_foreach): Pass the action
  target through to the loop's delegate, it's a bit more useful for
  dealing with the WK2 model.
  (add_g_menu_to_gtk_menu): Removed, WebKitContextMenu doesn't extend
  Gtk.Menu any longer so this is is no longer needed.

* ui/composer-menus.ui: Reoganise to use standard composer action
  prefix. Duplicate rich and plain text clipboard sections so they can
  just be selectively enabled. Include dummy sections for WK items to
  specify where they are located in the menu, and a section for the
  inspector.
2017-02-01 00:41:44 +11:00
Michael James Gratton
159e6c9bae Add is_rich_text property to ComposerWebView, use it.
* src/client/composer/composer-web-view.vala (ComposerWebView): Add
  is_rich_text pop, keep it updated.

* src/client/composer/composer-widget.vala (ComposerWidget): Use
  is_rich_text property rather than consulting the action's state.
2017-02-01 00:41:44 +11:00
Michael James Gratton
f69c461955 Re-enable spell checking in composer.
* src/client/application/geary-config.vala (Configuration): Remove
  spell-check setting, we can just get it from the list of visible
  languages instead. Update the schema.

* src/client/components/client-web-view.vala (WebView::init_web_context):
  Pass in a config object, use that to init WebKit's spell checking on
  the WebContext now that is a global configuration, update it when the
  config changes, update call sites.

* src/client/composer/composer-widget.vala (ComposerWidget): Remove
  WK1-syle spell checking settings prefs.

* src/client/composer/spell-check-popover.vala (SpellCheckPopover): Pass
  a config object in so we don't have to use the global app singleton
  instance.

* src/client/dialogs/preferences-dialog.vala (PreferencesDialog):
  Modernise by converting into a widget template.

* test/client/components/client-web-view-test-case.vala (TestCase):
  Construct a config object as a fixture, use it to init the WebContext
  and make it avalaible to subclasses & update subclasses.

* ui/preferences-dialog.ui: Moved from preferences.dialog, remove spell
  check preference.
2017-02-01 00:41:44 +11:00
Michael James Gratton
6171ff2ebd Fix attachments UI not ever being displayed.
* src/client/components/client-web-view.vala (ClientWebView): Make
  has_valid_height a GObject property so we can get notified about it
  changing.

* src/client/conversation-viewer/conversation-email.vala
  (ConversationEmail::connect_message_view_signals): Fixed to listen to
  has-valid-height changing rather than the old WK1 load-status property.

* ui/conversation-message.ui: Set body_container orientation to vertical
  so adding the attachments widget works as expected.
2017-02-01 00:41:43 +11:00
Michael James Gratton
636e514cda Minor code cleanup.
* src/client/components/client-web-view.vala (ClientWebView): Make some
  unnecessarily internal methods private.

* ui/*.js: Replace "var" with "let" where appropriate - i.e. almost
  everywhere.
2017-02-01 00:41:43 +11:00
Michael James Gratton
8864e2b7a7 Work around rendering quote controller buttons, enable expanding quotes.
* ui/conversation-web-view.js (ConversationPageState): Add
  ::updatePreferredHeight method to waitch for and update the web view's
  preferred height when it changes.
  (ConversationPageState::createControllableQuotes): Create quote
  controllers using the DOM so we can easily attach click handlers to
  it. Attach handlers to toggle the hide class and updated the preferred
  height.

* ui/client-web-view.js (PageState): Add ::getPreferredHeight method, use
  that to determine the preferred height of the page.

* ui/conversation-web-view.css: Import GTK+4 Adwaita button CSS to work
  around WebKitGTK+ Bug 166648. Tweak quote style a bit.
2017-02-01 00:41:43 +11:00
Michael James Gratton
5e114cfcac Fix being unable to scroll a message while remote images are loading.
* src/client/conversation-viewer/conversation-list-box.vala
  (EmailRow::on_size_allocate): Disable should-scroll when we have a
  valid height, not when loaded, so we stop pinning the scroll value and
  let users scroll, even when remote images loads are still running.

* src/client/components/client-web-view.vala (WebView): Replace is_loaded
  with has_valid_height, so we can if the body has been parsed and some
  content is visible. This still isn't perfect, but better than using
  load-ended. Fix call sites.
2017-02-01 00:41:43 +11:00
Michael James Gratton
e002f0c320 Add an OSD prgress bar for remote image loading.
* src/client/conversation-viewer/conversation-message.vala
  (ConversationMessage): Chase body container type and name change,
  update call sites. Add in a Progress bar and update it using callbacks
  from the web view, handling both initial load and the user subsequently
  giving permission to load remote images.

* src/client/components/client-web-view.vala (ClientWebView): Provide a
  form of the internal URL scheme prefix.

* ui/conversation-message.ui: Convert body container from being a GtkBox
  to a GtkGrid, add in a GtkProgressBar.
2017-02-01 00:41:43 +11:00
Michael James Gratton
271b9460ec Add Geary.TimeoutManager as a high-level interface to GLib.Timeout. 2017-02-01 00:41:43 +11:00
Michael James Gratton
977bb2827a Minor code cleanup. 2017-02-01 00:41:43 +11:00
Michael James Gratton
17fda41b85 Fix non-breaking spaces breaking formatting in sent messages.
This ensures that non-breaking space chars (not HTML entities) are
removed from text obtainined from the composer, and moves the F=F text
formatting from JS back to Vala, to minimimse the JS footprint and return
to using the old (working) version again.

* src/client/composer/composer-web-view.vala (ClientWebView::get_text):
  Restore the old F=F formatting code previously in webkit-util, apply it
  to plain text obtained from the composer.

* test/client/components/client-web-view-test-case.vala: New base class
  for tests involving ClientWebView.

* test/client/composer/composer-web-view-test.vala: New tests for
  ComposerWebView::get_html and ::get_text.

* test/js/composer-page-state-test.vala: Reworked to use
  ClientWebViewTestCase, updated tests now that JS is returning
  QUOTE_MARKER-delinated text, not F=F text.

* test/testcase.vala (TestCase): Move ::async_complete and ::async_result
  from ComposerPageStateTest so all test cases can test async code.

* test/CMakeLists.txt: Add new source files.

* test/main.vala (main): Add new test.

* ui/composer-web-view.js: Update doc comments, remove F=F code, break
  out non-breaking space replacement so it can be tested.
2017-02-01 00:41:43 +11:00
Michael James Gratton
57f10446a9 Use an internal URL scheme for displaying message bodies.
This makes debugging easier, since the URL will show up in the console,
Inspector and elsewhere, and the HTML message source, etc will appear in
the Inspector.

* src/client/components/client-web-view.vala
  (ClientWebView::init_web_context): Rehitser new internal scheme, hook
  it up to the new ::handle_internal_request handler for it.
  (ClientWebView::load_html): Keep a reference to the HTML body so it can
  be loaded via the URL scheme handler, make the second param optional
  and if null, use the new internal URL for the body part. Update call
  sites to avoid using the second param.

* src/client/web-process/web-process-extension.vala
  (GearyWebExtension::on_send_request): Allow requests for the
  internal URL scheme.
2017-02-01 00:41:43 +11:00
Michael James Gratton
536fb04840 Minor code updates. 2017-02-01 00:41:43 +11:00
Michael James Gratton
503ca3b478 Update Javascript memory management a bit.
* bindings/vapi/javascriptcore-4.0.vapi: Don't pretend JS.String will
  be unreff'ed by vala, it wont. Add JS.GlobalContext.retain, in case it
  wants to be used.

* src/client/components/client-web-view.vala
  (ClientWebView::ClientWebView): JavascriptResult instances are unref'ed
  when unowned.
2017-02-01 00:41:43 +11:00
Michael James Gratton
772b874def Clean up JavaScriptCore VAPI, client and engine code.
* bindings/vapi/javascriptcore-4.0.vapi: Make JS objects match their JSC
  definitions: move JSValueFoo methods to JS.Value, etc. Update call
  sites.

* src/client/util/util-webkit.vala: Move WebKit-specific common methods
  from ClientWebView here. Update call sites.

* src/engine/util/util-js.vala: Move JSC-specific common methods from
  ClientWebView and ComposerPageStateTest here. Update call sites.

* src/client/web-process/web-process-extension.vala: Check for and handle
  exceptions when calling JS code.

* src/CMakeLists.txt: Add new source files, make WebKit VAPI generation
  and engine compilation depend on JSC.
2017-02-01 00:41:43 +11:00
Michael James Gratton
22de6b122e Fix JS error getting F=F text from ComposerWebView. Add JS unit tests.
* ui/composer-web-view.js (ComposerPageState::resolveNesting): Apply JS
  RegExp globally, to match default GLib RegEx behaviour.

* test/js/composer-page-state-test.vala: New tests covering generation of
  HTML and F=F text from JS ComposerPageState object.

* test/CMakeLists.txt: Add the new test.

* test/main.vala (main): Add a test suite for JS tests, add the new test
  to it.

* src/client/components/client-web-view.vala (ClientWebView): Add a
  reason to the JSError domain for when a JS exception is thrown.

* bindings/vapi/javascriptcore-4.0.vapi (JS::Context): Add JS.Type and
  some additional methods needed for the unit tests. Move most
  GlobalContext methods to Context so we can pass the lowest common
  demominator around.
2017-02-01 00:41:43 +11:00
Michael James Gratton
5dc20f4273 Make GTK & async unit tests work by running them in a GTK+ main loop.
Include GResources in the build so they can be loaded.

Bug 776421.

* test/main.vala (main): Init GTK, start a main loop and run the tests in
  that.

* test/CMakeLists.txt: Include GResources in unit test binary so they can
  be loaded by tests, and since we can't compile them into the client
  static lib.
2017-02-01 00:41:43 +11:00
Michael James Gratton
61c8e5a105 Remove global GearyApplication instance from ClientWebView.
This is also needed to make the class and its subclasses unit testable.

* src/client/components/client-web-view.vala
  (ClientWebView::ClientWebView): Replace use of
  GearyApplication.instance.config with a constructor parameter. Update
  all subclassess and call sites to ensure the parameter is passed in.
2017-02-01 00:41:43 +11:00