Using `whitespace: pre-wrap` to format plain text email sometimes
causes additional width to be allocated by the plain text blocks that
then does not get used due to the constraints on the HTML element.
The allocated space remains however and hence an un-needed horizontal
scrollbar appears.
Using `break-spaces` instead seems to help since it allows breaks after
a space character, leading to the additional space not otherwise being
allocated.
Now that the `:focus-within` pseudoclass is supported, use this rather
than some custom JS to update custom HTML classes. This also prevents
spurious mutation events from firing.
By overriding ComposerPageState::getHtml to accept a parameter that
supports getting HTML with empty composer parts removed, cleanContent
can simply be made to linkify the page, thus allowing a ComposerWidget
to be re-used multiple times when sending an email.
Update ComposerPageState.htmlToText() to allow ignoring certain elements
if needed. Update tests to test the function directly rather than going
through ComposerPageState.toText().
Allow deleting only the selected part of a link, and modify the existing
link instead of inserting a new one if the user didn't select any text.
Also restructure the code to avoid always-true or always-false if
statements.
Fixes#591
Fixes LGTM warning: "Avoid automated semicolon insertion (93% of all
statements in the enclosing script have an explicit semicolon)."
Signed-off-by: Konstantin Kharlamov <Hi-Angel@yandex.ru>
The ComposerPageState JS object assumed that if no signature was present
when first loaded, that none ever would be. This broke changing the
signature when the composer was opened for an account without one, and
the from account was changed to an account with a sig.
Instead of including the signature as part of the loaded body, always
include just a skeleton signature DIV and ensure the signature is loaded
dynamically after the body has been loaded. Update code and tests to
match this assumption, and add a unit test for updating the sig.
Fixes#309
This allows using the same code for editing account signatures as for the
composer.
* src/client/components/client-web-view.vala (ClientWebView): Move both
command_stack_changed and document_modified signals here from
ComposerWebView, since they use the same underlying machinery to
emit. Move get_html() from ComposerWebView since we want to get to the
HTML when editing signatures. Override WebView.set_editable() so we can
enable/disable the signal machinery and hence not get change signals
emitted when enabling/disabling editing.
* ui/client-web-view.js (PageState): Mirror the changes above made to
ClientWebView.
* src/meson.build (geary_web_process): Ensure C args are passed through
web compiling the web extension.
This attempts to solve bug
[#714921](https://bugzilla.gnome.org/show_bug.cgi?id=714921).
They are available as two buttons on the format bar, next to font
options. The icons I used are taken from a free icons site just for demo
purposes and should be replaced by new icons. Also I did not include
hotkeys mainly because I could not come up with a good one, also they
are pretty uncommon I think.
Also added new icons to icons/CMakeLists.txt
Fixes a failing unit test with WebKitGTK 2.18.
* ui/composer-web-view.js (EditContext::init): Check for and strip both "
and ' from start and end of font-family string.
This lets us implement changing signatures and deleting bottom-quoted
messages without having to reload the whole view, and makes it possible
to target only the user's content when modifying for send, etc.
* src/client/composer/composer-web-view.vala (ComposerWebView): Move
composer CSS into composer-web-view.css resource file, load it when
loading JS resource and add it to the view's user content manager.
(ComposerWebView::load_html): Split up body, signature and quote into a
DIV container for each.
(ComposerWebView::linkify_content): Replaced with ::clean_content,
which will also tidy up internal markup before sending. Update call
site and unit test.
* src/engine/rfc822/rfc822-utils.vala (Geary.RFC822.Utils): Remove some
more obtrusive white space when sending replies/forwards.
* test/client/composer/composer-web-view-test.vala,
test/js/composer-page-state-test.vala: Update tests to expect new HTML
and text output from ComposerWebView and use of individual parts for
composer markup.
* ui/composer-web-view.js (ComposerPageState): Replace messageBody
property and uses with bodyPart, signaturePart and quotePart. Set these
content-editable on load. Move listeners from messageBody back to the
document.body so they also listen for events on the additional
parts. Keep track of text cursor location within the parts and set a
class if so, to work around the lack of :focus-inside support.
(ComposerPageState::updateSignature): Implement by updating the inner
content of the signature part.
(ComposerPageState::deleteQuotedMessage): Implement by removing the
quote part from the DOM tree.
(ComposerPageState::containsAttachmentKeyword): Consider only the
bodyPart when scanning for attachments, remove hacks for ignoring the
signature any any quoted message.
(ComposerPageState::linkifyContent): Mirror ClientWebView change and
replace with ::cleanContent. Ensure existing parts have contenteditable
and focus class removed, remove signature and quote parts if empty.
(ComposerPageState::getHtml): Generate HTML using clones of the three
parts, so we can rmeove contenteditable and focus classes without
modifying the actual DOM.
(ComposerPageState::selectionChanged): Update focus class on parts as
needed.
* src/client/composer/composer-web-view.vala (ComposerWebView): Add
::save_selection and ::free_selection to allow the selection to be
saved when inserting a link. Thunk calls to JS.
(ComposerWebView::insert_link): Add selection id param, pass through to
JS.
* src/client/composer/composer-widget.vala
(ComposerWidget::new_link_popover): Manage saving the editor's
selection, passing its id when inserting a link, freeing it
again. Convert into an async method so we can wait for the selection id
to get back from the WebProcess, update call sites.
(ComposerWidget::on_insert_link): Disconnect and reconnect selection
changed signal so the popover isn't dismissed when the selection does
change/
* ui/composer-web-view.js (ComposerPageState): Implement new
::saveSelection, ::freeSelection and selectionId param on ::insertLink.
* ui/composer-web-view.js (ComposerPageState): Break any blockquote
elements under the cursor when Enter is pressed, unless Shift is also
down.
* src/client/web-process/util-composer.vala: Removed, no longer used.
* src/client/composer/composer-web-view.vala (ComposerWebView): Rename
::linkify_document since it really only applies to editor content. Make
an asyc method so we can wait until its finished. Update call
sites. Thunk call to JS.
* src/client/web-process/util-composer.vala,
src/client/web-process/util-webkit.vala: Remove unused code.
* ui/composer-web-view.js (ComposerPageState): Add ::linkifyContent
method and ::linkify static method. Add unit tests.
* src/client/composer/composer-web-view.vala (ClientWebView): Replace
::undo_blockquote_style with ::indent_line.
* src/client/composer/composer-widget.vala (ComposerWidget::on_indent):
Call new ::indent_line method, rather than doing a execCommand and a
second JS thunking call to fix the markup.
* ui/composer-web-view.js: Also replace ::undoBlockquoteStyle with new
::indentLine method. Add unit test.
* src/client/composer/composer-web-view.vala (ComposerWebView): Add
::contains_attachment_keywords that thunks to JS, remove uneeded
::get_block_quote_representation method.
* src/client/composer/composer-widget.vala (ComposerWidget): Remove
attachment keywork checking related code, just call new method on
editor to do the check.
* src/client/web-process/util-composer.vala,
src/client/web-process/util-webkit.vala: Remove uneeded code.
* ui/composer-web-view.js (ComposerPageState): Implement new
::containsAttachmentKeyword method based on previous code. Add unit
tests.
The main gist of this is to ensure that the composer's widgets are
constructed seperately to loading its content, and that we only ever call
ComposerWebView::load_html precisely once per composer instance.
* src/client/composer/composer-widget.vala: Remove referred message,
quote text and draft flag param from constructor signature, move any
calls that loaded data from them to new load method. Don't load
anything into the editor here. Make loading the signature file async,
and call new ComposerWebView::updateSignature method on the editor to
update it.
(ComposerWidget::load): New async message for loading content into the
composer. Move related code from the constructor and GearyController
here, make methods that were previously public for that private
again. Tidy up calls a bit now that we have a single place from which
to do it all, and can understand the process a bit better.
(ComposerWidget::on_editor_key_press_event): Don't reload the editor to
remove the quoted text, call new ComposerWebView::delete_quoted_message
method on it instead.
* src/client/composer/composer-web-view.vala
(ComposerWebView): Add ::delete_quoted_message ::update_signature
methods, thunk to JS.
(ComposerWebView::load_html): Add quote and is_draft parameters,
construct HTML for the composer using apporporate spacing here, instead
of relying on all the disparate parts from doing the right thing.
* src/client/application/geary-controller.vala
(GearyController::create_compose_widget_async): Load composer content
after adding it to the widget hierarchy, set focus only after
everything is set up.
* src/engine/rfc822/rfc822-utils.vala (quote_email_for_reply,
quote_email_for_forward): Don't add extra padding around quoted parts -
let callers manage their own whitespace.
* test/client/components/client-web-view-test-case.vala
(TestCase:load_body_fixture): Make HTML param non-nullable, update
subclasses.
* ui/composer-web-view.js (ComposerPageState): Add ::updateSignature and
::deleteQuotedMessage method stubs.
* ui/client-web-view.js (PageState): Use event listeners to send
coalesced preferred height changes, rather than using polling. Call
::load on DOM loaded, not on complete page loaded, so in-place
mutations take affect ASAP. Replace ::preferredHeightChanged with
::updatePreferredHeight method that checks that the height has changed
before sending the message to the app.
* ui/composer-web-view.js: Remove loaded event handler, it's managed by
the base class now.
* ui/conversation-web-view.js (ConversationPageState): Rename
::updatePreferredHeight to ::pollPreferredHeightUpdate to avoid name
clash with parent class. Stop polling if no change has occurred after a
number of repeated checks. Remove loaded event handler, it's managed by
the base class now.
(ComposerPageState::createControllableQuotes): Don't update preferred
height at the end of the call since it will be handled by the DOM load
event handler.
* src/client/composer/composer-widget.vala
(ComposerWidget::on_button_press): Show a link popover on button
release.
* src/client/composer/composer-web-view.vala (ComposerWebView): Add
button_release_event_done signal to work around WK eating mouse events,
fire it after default processing has occurred.
* ui/composer-web-view.js: Don't bother selecting a link on click, we
are handling insertion and deletion without it fine now. Just cancel
the event's default so link clicks are not activated.
* src/client/composer/composer-web-view.vala (ComposerWebView): Call
new ComposerPageState methods for ::insert_link and ::delete_link.
* ui/composer-web-view.js (ComposerPageState): Add new ::insertLink
and ::deleteLink methods, handle linking/unlinking both the
current selection and the link under the text cursor, if nothing
is selected.
* src/client/composer/composer-link-popover.vala: New GtkPopover subclass
for creating/editing links.
* src/client/composer/composer-web-view.vala (EditContext): Add is_link
and link_uri properties, decode them from the message string, add
decoding tests.
(ComposerWebView): Add some as-yet un-implemented methods for
inserting/deleting links.
* src/client/composer/composer-widget.vala (ComposerWidget): Add
cursor_url for storing current text cursor link, update it from the
cursor_context_changed signal param, rename hover_url to pointer_url to
match. Add link_activated signal to let user's open links they are
adding, hook that up in the controller. Rename
::update_selection_actions to ::update_cursor_actions, since that's a
little more apt now, also enable insert link action if there is a
cursor_url set as well as a selection. Remove ::link_dialog, replace
with ::new_link_popover, hook up the new popover's signals there as
appropriate.
(ComposerWidget::on_insert_link): Create and show a lin popover instead
of a dialog.
* ui/composer-web-view.js: Take note of whther the context node is a link
and if so, also it's href. Include both when serialsing for the
cursorContextChanged message. Add serialisation tests.
* ui/composer-link-popover.ui: New UI for link popover.
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.
* 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.
* 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.
* 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.
* 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.
* 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.
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.