mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-01-01 13:14:16 +08:00
363 lines
15 KiB
HTML
363 lines
15 KiB
HTML
---
|
|
layout: docs
|
|
title: DraftStoreExtension
|
|
edit_url: "https://github.com/nylas/N1/blob/master/src/flux/stores/draft-store-extension.coffee"
|
|
---
|
|
|
|
<h2>Summary</h2>
|
|
|
|
<div class="markdown-from-sourecode">
|
|
<p><p>DraftStoreExtension is an abstract base class. To create DraftStoreExtensions
|
|
that enhance the composer experience, you should subclass <a href='draftstoreextension.html'>DraftStoreExtension</a> and
|
|
implement the class methods your plugin needs.</p>
|
|
<p>To register your extension with the DraftStore, call <a href='DraftStore.html#registerExtension'>DraftStore::registerExtension</a>.
|
|
When your package is being unloaded, you <em>must</em> call the corresponding
|
|
<a href='DraftStore.html#unregisterExtension'>DraftStore::unregisterExtension</a> to unhook your extension.</p>
|
|
<pre><code class="lang-coffee">activate: ->
|
|
DraftStore.<span class="hljs-function"><span class="hljs-title">registerExtension</span><span class="hljs-params">(MyExtension)</span></span>
|
|
|
|
...
|
|
|
|
deactivate: ->
|
|
DraftStore.<span class="hljs-function"><span class="hljs-title">unregisterExtension</span><span class="hljs-params">(MyExtension)</span></span>
|
|
</code></pre>
|
|
<p>Your DraftStoreExtension subclass should be stateless. The user may have multiple drafts
|
|
open at any time, and the methods of your DraftStoreExtension may be called for different
|
|
drafts at any time. You should not expect that the session you receive in
|
|
<a href='#finalizeSessionBeforeSending'>finalizeSessionBeforeSending</a> is for the same draft you previously received in
|
|
<a href='#warningsForSending'>warningsForSending</a>, etc.</p>
|
|
<p>The DraftStoreExtension API does not currently expose any asynchronous or <a href='https://github.com/petkaantonov/bluebird/blob/master/API.md'>Promise</a>-based APIs.
|
|
This will likely change in the future. If you have a use-case for a Draft Store extension that
|
|
is not possible with the current API, please let us know.</p>
|
|
</p>
|
|
</div>
|
|
|
|
<ul>
|
|
</ul>
|
|
|
|
|
|
|
|
<h3>Class Methods</h3>
|
|
|
|
<h4 id=warningsForSending class="function-name">
|
|
warningsForSending(<span class="args"><span class="arg">draft</span></span>) <a href="#warningsForSending" class="link"></a>
|
|
</h4>
|
|
|
|
<div class="function-description markdown-from-sourecode">
|
|
<p><p>Inspect the draft, and return any warnings that need to be displayed before
|
|
the draft is sent. Warnings should be string phrases, such as "without an attachment"
|
|
that fit into a message of the form: "Send #{phase1} and #{phase2}?"</p>
|
|
</p>
|
|
</div>
|
|
|
|
<strong>Parameters</strong>
|
|
<table class="arguments">
|
|
<tr>
|
|
<th>Argument</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>draft</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>A fully populated <a href='message.html'>Message</a> object that is about to be sent.</p>
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<strong>Returns</strong>
|
|
<table class="arguments">
|
|
<tr>
|
|
<th>Return Values</th>
|
|
</tr>
|
|
<tr><td class="markdown-from-sourecode"><p>Returns a list of warning strings, or an empty array if no warnings need to be displayed.</p>
|
|
</td></tr>
|
|
</table>
|
|
<h4 id=composerToolbar class="function-name">
|
|
composerToolbar(<span class="args"><span class="arg">mutator</span><span class="arg">tooltip</span><span class="arg">iconUrl</span></span>) <a href="#composerToolbar" class="link"></a>
|
|
</h4>
|
|
|
|
<div class="function-description markdown-from-sourecode">
|
|
<p><p>declare an icon to be displayed in the composer's toolbar (where
|
|
bold, italic, underline, etc are).</p>
|
|
<p>You must declare the following properties:</p>
|
|
</p>
|
|
</div>
|
|
|
|
<strong>Parameters</strong>
|
|
<table class="arguments">
|
|
<tr>
|
|
<th>Argument</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>mutator</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>A function that's called when your toolbar button is clicked. This mutator function will be passed as its only argument the <code>dom</code>. The <code>dom</code> is the full {DOM} object of the current composer. You may mutate this in place. We don't care about the mutator's return value.</p>
|
|
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>tooltip</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>A one or two word description of what your icon does</p>
|
|
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>iconUrl</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The url of your icon. It should be in the <code>nylas://</code> scheme. For example: <code>nylas://your-package-name/assets/my-icon@2x.png</code>. Note, we will downsample your image by 2x (for Retina screens), so make sure it's twice the resolution. The icon should be black and white. We will directly pass the <code>url</code> prop of a <a href='retinaimg.html'>RetinaImg</a></p>
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h4 id=prepareNewDraft class="function-name">
|
|
prepareNewDraft(<span class="args"></span>) <a href="#prepareNewDraft" class="link"></a>
|
|
</h4>
|
|
|
|
<div class="function-description markdown-from-sourecode">
|
|
<p><p>Override prepareNewDraft to modify a brand new draft before it is displayed
|
|
in a composer. This is one of the only places in the application where it's safe
|
|
to modify the draft object you're given directly to add participants to the draft,
|
|
add a signature, etc.</p>
|
|
<p>By default, new drafts are considered <code>pristine</code>. If the user leaves the composer
|
|
without making any changes, the draft is discarded. If your extension populates
|
|
the draft in a way that makes it "populated" in a valuable way, you should set
|
|
<code>draft.pristine = false</code> so the draft saves, even if no further changes are made.</p>
|
|
</p>
|
|
</div>
|
|
|
|
|
|
<h4 id=finalizeSessionBeforeSending class="function-name">
|
|
finalizeSessionBeforeSending(<span class="args"><span class="arg">session</span></span>) <a href="#finalizeSessionBeforeSending" class="link"></a>
|
|
</h4>
|
|
|
|
<div class="function-description markdown-from-sourecode">
|
|
<p><p>Override finalizeSessionBeforeSending in your DraftStoreExtension subclass to transform
|
|
the <a href='draftstoreproxy.html'>DraftStoreProxy</a> editing session just before the draft is sent. This method
|
|
gives you an opportunity to make any final substitutions or changes after any
|
|
<a href='#warningsForSending'>warningsForSending</a> have been displayed.</p>
|
|
<p>Example:</p>
|
|
<pre><code class="lang-coffee"><span class="hljs-comment"># Remove any <code> tags found in the draft body</span>
|
|
<span class="hljs-attribute">finalizeSessionBeforeSending</span>: <span class="hljs-function"><span class="hljs-params">(session)</span> -></span>
|
|
body = session.draft().body
|
|
clean = body.replace(<span class="hljs-regexp">/<\/?code[^>]*>/g</span>, <span class="hljs-string">''</span>)
|
|
<span class="hljs-keyword">if</span> body != clean
|
|
session.changes.add(<span class="hljs-attribute">body</span>: clean)
|
|
</code></pre>
|
|
</p>
|
|
</div>
|
|
|
|
<strong>Parameters</strong>
|
|
<table class="arguments">
|
|
<tr>
|
|
<th>Argument</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>session</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>A <a href='draftstoreproxy.html'>DraftStoreProxy</a> for the draft.</p>
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h4 id=onMouseUp class="function-name">
|
|
onMouseUp(<span class="args"><span class="arg">editableNode</span><span class="arg">range</span><span class="arg">event</span></span>) <a href="#onMouseUp" class="link"></a>
|
|
</h4>
|
|
|
|
<div class="function-description markdown-from-sourecode">
|
|
<p><p>Override onMouseUp in your DraftStoreExtension subclass to
|
|
listen for mouse up events sent to the composer's body text area. This
|
|
hook provides the contenteditable DOM Node itself, allowing you to
|
|
adjust selection ranges and change content as necessary.</p>
|
|
</p>
|
|
</div>
|
|
|
|
<strong>Parameters</strong>
|
|
<table class="arguments">
|
|
<tr>
|
|
<th>Argument</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>editableNode</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The composer's contenteditable <a href='https://developer.mozilla.org/en-US/docs/Web/API/Node'>Node</a> that received the event.</p>
|
|
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>range</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The currently selected <a href='https://developer.mozilla.org/en-US/docs/Web/API/Range'>Range</a> in the <code>editableNode</code></p>
|
|
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>event</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The mouse up event.</p>
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h4 id=onFocusPrevious class="function-name">
|
|
onFocusPrevious(<span class="args"><span class="arg">editableNode</span><span class="arg">range</span><span class="arg">event</span></span>) <a href="#onFocusPrevious" class="link"></a>
|
|
</h4>
|
|
|
|
<div class="function-description markdown-from-sourecode">
|
|
<p><p>Called when the user presses <code>Shift-Tab</code> while focused on the composer's body field.
|
|
Override onFocusPrevious in your DraftStoreExtension to adjust the selection or perform
|
|
other actions. If your package implements Shift-Tab behavior in a particular scenario, you
|
|
should prevent the default behavior of Shift-Tab via <code>event.preventDefault()</code>.</p>
|
|
</p>
|
|
</div>
|
|
|
|
<strong>Parameters</strong>
|
|
<table class="arguments">
|
|
<tr>
|
|
<th>Argument</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>editableNode</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The composer's contenteditable <a href='https://developer.mozilla.org/en-US/docs/Web/API/Node'>Node</a> that received the event.</p>
|
|
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>range</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The currently selected <a href='https://developer.mozilla.org/en-US/docs/Web/API/Range'>Range</a> in the <code>editableNode</code></p>
|
|
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>event</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The mouse up event.</p>
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h4 id=onFocusNext class="function-name">
|
|
onFocusNext(<span class="args"><span class="arg">editableNode</span><span class="arg">range</span><span class="arg">event</span></span>) <a href="#onFocusNext" class="link"></a>
|
|
</h4>
|
|
|
|
<div class="function-description markdown-from-sourecode">
|
|
<p><p>Called when the user presses <code>Tab</code> while focused on the composer's body field.
|
|
Override onFocusPrevious in your DraftStoreExtension to adjust the selection or perform
|
|
other actions. If your package implements Tab behavior in a particular scenario, you
|
|
should prevent the default behavior of Tab via <code>event.preventDefault()</code>.</p>
|
|
</p>
|
|
</div>
|
|
|
|
<strong>Parameters</strong>
|
|
<table class="arguments">
|
|
<tr>
|
|
<th>Argument</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>editableNode</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The composer's contenteditable <a href='https://developer.mozilla.org/en-US/docs/Web/API/Node'>Node</a> that received the event.</p>
|
|
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>range</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The currently selected <a href='https://developer.mozilla.org/en-US/docs/Web/API/Range'>Range</a> in the <code>editableNode</code></p>
|
|
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width:15%;">
|
|
<em>event</em>
|
|
</td>
|
|
<td class="markdown-from-sourecode">
|
|
|
|
<p>The mouse up event.</p>
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h4 id=onInput class="function-name">
|
|
onInput(<span class="args"></span>) <a href="#onInput" class="link"></a>
|
|
</h4>
|
|
|
|
<div class="function-description markdown-from-sourecode">
|
|
<p><p>Override onInput in your DraftStoreExtension subclass to
|
|
implement custom behavior as the user types in the composer's
|
|
contenteditable body field.</p>
|
|
<p>As the first argument you are passed the entire DOM object of the
|
|
composer. You may mutate this object and edit it in place.</p>
|
|
<p>Example:</p>
|
|
<p>The Nylas <code>templates</code> package uses this method to see if the user has populated a
|
|
<code><code></code> tag placed in the body and change it's CSS class to reflect that it is no
|
|
longer empty.</p>
|
|
<pre><code class="lang-coffee">onInput: (editableNode, event) ->
|
|
selection = document.<span class="hljs-function"><span class="hljs-title">getSelection</span><span class="hljs-params">()</span></span>
|
|
|
|
isWithinNode = (node) ->
|
|
test = selection<span class="hljs-class">.baseNode</span>
|
|
while test isnt editableNode
|
|
return true <span class="hljs-keyword">if</span> test is node
|
|
test = test<span class="hljs-class">.parentNode</span>
|
|
return false
|
|
|
|
codeTags = editableNode.<span class="hljs-function"><span class="hljs-title">querySelectorAll</span><span class="hljs-params">(<span class="hljs-string">'code.var.empty'</span>)</span></span>
|
|
<span class="hljs-keyword">for</span> codeTag <span class="hljs-keyword">in</span> codeTags
|
|
<span class="hljs-keyword">if</span> selection.<span class="hljs-function"><span class="hljs-title">containsNode</span><span class="hljs-params">(codeTag)</span></span> or <span class="hljs-function"><span class="hljs-title">isWithinNode</span><span class="hljs-params">(codeTag)</span></span>
|
|
codeTag<span class="hljs-class">.classList</span><span class="hljs-class">.remove</span>(<span class="hljs-string">'empty'</span>)
|
|
</code></pre>
|
|
</p>
|
|
</div>
|