1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-23 01:12:19 -05:00

Merge pull request #81 from whiteout-io/dev/performance

Dev/performance
This commit is contained in:
Tankred Hase 2014-06-27 14:45:19 +02:00
commit f117c78d36
24 changed files with 171 additions and 81 deletions

View File

@ -6,4 +6,4 @@ cd ..
cd release/cca/Whiteout
#cca run ios
cca run android
cca run android --device

View File

@ -275,6 +275,29 @@ define(function(require) {
var ngModule = angular.module('mail-list', []);
ngModule.directive('woTouch', function($parse) {
return function(scope, elm, attrs) {
var handler = $parse(attrs.woTouch);
elm.on('touchstart', function() {
elm.addClass('active');
});
elm.on('touchleave touchcancel touchmove', function() {
elm.removeClass('active');
});
elm.on('touchend click', function(event) {
event.preventDefault();
elm.removeClass('active');
scope.$apply(function() {
handler(scope, {
$event: event
});
});
});
};
});
ngModule.directive('listScroll', function() {
return {
link: function(scope, elm, attrs) {

View File

@ -31,8 +31,8 @@
&.active {
background-image: none;
box-shadow: none;
top: 1px;
right: -1px;
top: 2px;
right: -2px;
}
&.disabled,
@ -104,12 +104,14 @@
font-size: $font-size-base;
font-family: $font-family-icons;
line-height: 1;
height: 2em;
width: 2em;
height: 2.5em;
width: 2.5em;
text-align: center;
-webkit-font-smoothing: antialiased;
@include respond-to(desktop) {
transition: color 0.3s;
transform: translate3d(0,0,0); // to prevent flickering
}
outline: none;
&.disabled,
@ -124,8 +126,8 @@
&:active,
&.active {
outline: 0;
top: 1px;
left: 1px;
top: 2px;
right: -2px;
}
&:after {
@ -141,10 +143,13 @@
padding: 2px;
z-index: -1;
background: $btn-icon-color;
@include respond-to(desktop) {
transition: transform 0.3s, opacity 0.4s;
transform: scale(1.2);
}
opacity: 0;
}
@include respond-to(desktop) {
&:hover {
color: $color-white;
&:after {
@ -153,3 +158,4 @@
}
}
}
}

View File

@ -5,7 +5,9 @@
width: 100%;
height: 100%;
z-index: 2000;
@include respond-to(desktop) {
backface-visibility: hidden;
}
@include respond-to(desktop) {
margin: 0 auto;
@ -37,10 +39,15 @@
display: block;
border: none;
background: none;
padding: 0;
padding: 0 0 0 40px;
margin: 0;
color: $color-grey-dark;
outline: none;
&.active {
top: 2px;
right: -2px;
}
}
h2 {
margin: 0;
@ -81,12 +88,16 @@
&.show-add {
display: block;
opacity: 0;
@include respond-to(desktop) {
transition: opacity 0.3s;
}
.lightbox-body {
transform: scale(0.7);
@include respond-to(desktop) {
transition: transform 0.3s;
}
}
}
&.show-add-active {
opacity: 1;
.lightbox-body {
@ -96,12 +107,16 @@
&.show-remove {
display: block;
opacity: 1;
@include respond-to(desktop) {
transition: opacity 0.3s;
}
.lightbox-body {
transform: scale(1);
@include respond-to(desktop) {
transition: transform 0.3s;
}
}
}
&.show-remove-active {
opacity: 0;
.lightbox-body {

View File

@ -12,7 +12,7 @@
padding: $padding-vertical $padding-horizontal;
background: $color-white;
cursor: pointer;
transition: background-color $time-li-fade, color $time-li-fade;
//transition: background-color $time-li-fade, color $time-li-fade;
margin-top: 11px;
&:before {
@ -120,8 +120,9 @@
overflow: hidden;
}
&.active,
&:hover {
background-color: mix($color-white, $color-blue, 90%);
background-color: mix($color-white, $color-blue, 85%);
}
&.mail-list-active,

View File

@ -12,15 +12,19 @@
left: 0;
z-index: 99;
height: 100%;
@include respond-to(desktop) {
transition: transform $time-nav-animation;
}
}
.nav-menu-open .nav-pusher::after {
width: 100%;
height: 100%;
opacity: 1;
@include respond-to(desktop) {
transition: opacity $time-nav-animation;
}
}
.nav-pusher::after {
position: absolute;
@ -31,8 +35,10 @@
background: rgba(0,0,0,0.2);
content: '';
opacity: 0;
@include respond-to(desktop) {
transition: opacity $time-nav-animation, width 0.1s $time-nav-animation, height 0.1s $time-nav-animation;
}
}
.nav-menu {
position: absolute;
@ -45,7 +51,9 @@
height: 100%;
background: $color-blue;
background-image: linear-gradient(to right ,$color-blue 98%, darken($color-blue, 1%) 100%);
@include respond-to(desktop) {
transition: all $time-nav-animation;
}
border-right: 1px solid $color-grey-light;
}
@ -65,7 +73,9 @@
.nav-effect.nav-menu-open .nav-effect.nav-menu {
visibility: visible;
@include respond-to(desktop) {
transition: transform $time-nav-animation;
}
transform: translate3d(0, 0, 0);
}

View File

@ -12,6 +12,10 @@
flex-shrink: 0;
cursor: pointer;
padding: $padding-vertical $padding-horizontal;
@include respond-to(mobile) {
padding: ($padding-vertical + 5px) $padding-horizontal;
}
&:before {
color: $color-blue;
font-size: $font-size-bigger;
@ -27,13 +31,34 @@
vertical-align: middle;
text-shadow: 0px 1px 1px $color-grey-lighter;
}
button {
float: right;
&.active {
background-color: darken($color-white, 10%);
}
}
.compose {
position: absolute;
top: $padding-vertical;
right: $padding-horizontal;
margin-top: -0.05em; // for perfect vertical alignment with headline
padding-left: 40px;
&.active {
top: $padding-vertical + 2px;
right: $padding-horizontal - 2px;
}
@include respond-to(desktop) {
display: none;
}
button {
&:active,
&.active {
top: 0;
right: 0;
}
}
}
@ -60,6 +85,7 @@
flex-grow: 1;
padding: 0 ($padding-horizontal - $scrollbar-width) 0 $padding-horizontal;
overflow-y: scroll;
transform: translatez(0);
}
footer {

View File

@ -65,8 +65,8 @@
vertical-align: middle;
text-shadow: none;
}
&:hover, &:focus {
background-color: mix($color-blue, $color-white, 80%);
&.active, &:hover, &:focus {
background-color: mix($color-blue, $color-white, 70%);
}
}
}

View File

@ -24,6 +24,10 @@
display: none;
}
}
&.active {
background-color: darken($color-white, 10%);
}
}
.date {
@ -46,7 +50,6 @@
.controls {
float: right;
margin: 0 15px 10px;
button {
margin-left: 7px;
@ -137,6 +140,7 @@
line-height: 1.5em;
overflow-y: scroll;
user-select: text;
transform: translatez(0);
.line {
cursor: text;

View File

@ -1,6 +1,6 @@
<div class="lightbox-body" ng-controller="AboutCtrl">
<header>
<button class="close" ng-click="state.about.toggle(false)" data-action="lightbox-close">&#xe007;</button>
<button class="close" wo-touch="state.about.toggle(false)" data-action="lightbox-close">&#xe007;</button>
</header>
<div class="content">

View File

@ -1,7 +1,7 @@
<div class="lightbox-body" ng-controller="AccountCtrl">
<header>
<h2>Account</h2>
<button class="close" ng-click="state.account.toggle(false)" data-action="lightbox-close">&#xe007;</button>
<button class="close" wo-touch="state.account.toggle(false)" data-action="lightbox-close">&#xe007;</button>
</header>
<div class="content">
@ -29,8 +29,8 @@
</table>
<div class="control">
<button ng-click="state.account.toggle(false); state.setPassphrase.toggle(true)" class="btn btn-alt">Set passphrase</button>
<button ng-click="exportKeyFile()" class="btn">Export keypair</button>
<button wo-touch="state.account.toggle(false); state.setPassphrase.toggle(true)" class="btn btn-alt">Set passphrase</button>
<button wo-touch="exportKeyFile()" class="btn">Export keypair</button>
</div>
</div><!-- /.view-account -->

View File

@ -3,7 +3,7 @@
<h1>Select email account</h1>
<ul>
<li class="google enabled" popover="#google-info" ng-click="connectToGoogle()">
<li class="google enabled" popover="#google-info" wo-touch="connectToGoogle()">
<div><img src="img/google_logo.png" alt="Google Mail"></div>
</li>
<li class="whiteout disabled" popover="#whiteout-info">

View File

@ -1,7 +1,7 @@
<div class="lightbox-body" ng-controller="ContactsCtrl">
<header>
<h2>Contacts</h2>
<button class="close" ng-click="state.contacts.toggle(false)" data-action="lightbox-close">&#xe007;</button>
<button class="close" wo-touch="state.contacts.toggle(false)" data-action="lightbox-close">&#xe007;</button>
</header>
<div class="content">
@ -31,7 +31,7 @@
<td>{{key.userId}}</td>
<td>{{key.created | date:'mediumDate'}}</td>
<td>{{key.bitSize}} bit</td>
<td><button class="remove" ng-click="removeKey(key)">&#xe007;</button></td>
<td><button class="remove" wo-touch="removeKey(key)">&#xe007;</button></td>
</tr>
</table>
</div><!--/.key-list-scroll-->

View File

@ -1,14 +1,14 @@
<div class="lightbox-body" ng-controller="DialogCtrl">
<header>
<h2>{{state.dialog.title}}</h2>
<button class="close" ng-click="confirm(false)" data-action="lightbox-close">&#xe007;</button>
<button class="close" wo-touch="confirm(false)" data-action="lightbox-close">&#xe007;</button>
</header>
<div class="content">
<p>{{state.dialog.message}}</p>
<div class="control">
<button ng-click="confirm(false)" class="btn btn-alt" ng-show="state.dialog.showNegativeBtn">{{state.dialog.negativeBtnStr}}</button>
<button ng-click="confirm(true)" class="btn">{{state.dialog.positiveBtnStr}}</button>
<button wo-touch="confirm(false)" class="btn btn-alt" ng-show="state.dialog.showNegativeBtn">{{state.dialog.negativeBtnStr}}</button>
<button wo-touch="confirm(true)" class="btn">{{state.dialog.positiveBtnStr}}</button>
</div>
</div><!-- /.content -->
</div><!-- /.lightbox-body -->

View File

@ -13,7 +13,7 @@
</div>
<a href="https://whiteout.io/revocation.html" title="Click here to reset your account." target="_blank">Forgot your passphrase?</a>
<div>
<button type="submit" ng-click="confirmPassphrase()" class="btn" data-icon="&#xe009;" ng-disabled="!buttonEnabled" tabindex="2">Unlock</button>
<button type="submit" wo-touch="confirmPassphrase()" class="btn" data-icon="&#xe009;" ng-disabled="!buttonEnabled" tabindex="2">Unlock</button>
</div>
</form>
</div><!--/content-->

View File

@ -6,7 +6,7 @@
<div class="content" ng-switch on="state.ui">
<div ng-switch-when="1">
<p><b>Generate PGP key.</b> You can set a passphrase to protect your key on disk. This must be entered everytime you start the app. For no passphrase just press continue.</p><p>Alternatively you can also <a href="#" ng-click="$event.preventDefault(); importKey()">import an existing PGP key</a>.</p>
<p><b>Generate PGP key.</b> You can set a passphrase to protect your key on disk. This must be entered everytime you start the app. For no passphrase just press continue.</p><p>Alternatively you can also <a href="#" wo-touch="$event.preventDefault(); importKey()">import an existing PGP key</a>.</p>
<form>
<div>
<label class="input-error-message" ng-class="{'passphrase-label-ok': passphraseRating >= 2}">{{passphraseMsg}}</label><br>
@ -21,7 +21,7 @@
</div>
<div>
<button type="submit" ng-click="confirmPassphrase()" class="btn" ng-disabled="(state.confirmation || state.passphrase) && state.confirmation !== state.passphrase" tabindex="3">Continue</button>
<button type="submit" wo-touch="confirmPassphrase()" class="btn" ng-disabled="(state.confirmation || state.passphrase) && state.confirmation !== state.passphrase" tabindex="3">Continue</button>
</div>
</form>
</div>

View File

@ -16,7 +16,7 @@
<span class="popover-info" data-icon-append="&#xe010;" popover="#passphrase-info"></span>
</div>
<a href="https://whiteout.io/revocation.html" title="Click here to reset your account." target="_blank">Lost your keyfile or passphrase?</a>
<div><button type="submit" ng-click="confirmPassphrase()" class="btn" ng-disabled="!key" tabindex="3">Import</button>
<div><button type="submit" wo-touch="confirmPassphrase()" class="btn" ng-disabled="!key" tabindex="3">Import</button>
</form>
</div>
</div>

View File

@ -23,7 +23,7 @@
</div>
<div>
<button class="btn" ng-click="goForward()">Continue</button>
<button class="btn" wo-touch="goForward()">Continue</button>
</div>
</div><!--/content-->

View File

@ -1,17 +1,22 @@
<div class="view-mail-list" ng-controller="MailListCtrl">
<!-- nav controll and section headline -->
<header data-icon="&#xe004;" ng-click="state.nav.toggle(true); $event.stopPropagation()">
<header data-icon="&#xe004;" wo-touch="state.nav.toggle(true); $event.stopPropagation()">
<h2>{{state.nav.currentFolder.type}}</h2>
<button ng-click="state.writer.write(); $event.stopPropagation()" class="btn-icon" title="New mail"></button>
</header>
<div class="compose" wo-touch="state.writer.write(); $event.stopPropagation()">
<button class="btn-icon" title="New mail"></button>
</div>
<div class="search" data-icon="&#xe017;">
<input class="input-text" type="text" ng-model="searchText" placeholder="Filter..." focus-me="state.mailList.searching">
</div>
<div class="list-wrapper" list-scroll="filteredMessages">
<ul class="mail-list">
<li ng-class="{'mail-list-active': email === state.mailList.selected}" ng-click="select(email)" ng-repeat="email in (filteredMessages = (state.nav.currentFolder.messages | filter:searchText | orderBy:'uid':true | limitTo:100))">
<li ng-class="{'mail-list-active': email === state.mailList.selected}"
wo-touch="select(email)"
ng-repeat="email in (filteredMessages = (state.nav.currentFolder.messages | filter:searchText | orderBy:'uid':true | limitTo:100))">
<h3>{{email.from[0].name || email.from[0].address}}</h3>
<div class="encrypted" data-icon="{{email.encrypted && email.decrypted ? '&#xe012;' : email.encrypted ? '&#xe009;' : ''}}"></div>
<div class="head">

View File

@ -5,7 +5,7 @@
<ul class="nav-primary">
<li ng-repeat="folder in account.folders" ng-switch="folder.count !== undefined && folder.count > 0">
<a href="#" ng-click="openFolder(folder); $event.preventDefault()">
<a href="#" wo-touch="openFolder(folder); $event.preventDefault()">
{{folder.type}}
<span class="label-wrapper" ng-switch-when="true">
<span class="label label-light">{{folder.count}}</span>
@ -15,10 +15,10 @@
</ul>
<ul class="nav-secondary">
<li><a href="#" ng-click="state.account.toggle(true); $event.preventDefault()">Account</a></li>
<li><a href="#" ng-click="state.contacts.toggle(true); $event.preventDefault()">Contacts</a></li>
<li><a href="#" ng-click="state.privateKeyUpload.toggle(true); $event.preventDefault()">Key sync (experimental)</a></li>
<li><a href="#" ng-click="state.about.toggle(true); $event.preventDefault()">About</a></li>
<li><a href="#" wo-touch="state.account.toggle(true); $event.preventDefault()">Account</a></li>
<li><a href="#" wo-touch="state.contacts.toggle(true); $event.preventDefault()">Contacts</a></li>
<li><a href="#" wo-touch="state.privateKeyUpload.toggle(true); $event.preventDefault()">Key sync (experimental)</a></li>
<li><a href="#" wo-touch="state.about.toggle(true); $event.preventDefault()">About</a></li>
</ul>
<footer>

View File

@ -1,7 +1,7 @@
<div class="lightbox-body" ng-controller="PrivateKeyUploadCtrl">
<header>
<h2>Setup Key Sync</h2>
<button class="close" ng-click="state.privateKeyUpload.toggle(false)" data-action="lightbox-close">&#xe007;</button>
<button class="close" wo-touch="state.privateKeyUpload.toggle(false)" data-action="lightbox-close">&#xe007;</button>
</header>
<div class="content">
@ -37,8 +37,8 @@
</div>
<div class="control">
<button ng-show="step > 1 && step < 4" class="btn btn-alt" ng-click="goBack()">Go back</button>
<button ng-show="step < 4" class="btn" ng-click="goForward()">Continue</button>
<button ng-show="step > 1 && step < 4" class="btn btn-alt" wo-touch="goBack()">Go back</button>
<button ng-show="step < 4" class="btn" wo-touch="goForward()">Continue</button>
</div>
</div><!-- /.view-privatekey-upload -->

View File

@ -2,30 +2,30 @@
<div class="headers">
<div class="controls">
<button ng-click="state.mailList.remove(state.mailList.selected)" class="btn-icon" title="Delete mail">&#xe005;</button>
<button wo-touch="state.mailList.remove(state.mailList.selected)" class="btn-icon" title="Delete mail">&#xe005;</button>
<button class="btn-icon" title="Reply to" reply-selection>&#xe002;</button>
<button ng-click="state.writer.write()" class="btn-icon" title="New mail">&#xe006;</button>
<button wo-touch="state.writer.write()" class="btn-icon" title="New mail">&#xe006;</button>
</div><!--/.controls-->
<p class="subject" ng-click="state.read.toggle(false)" data-icon="&#xe016;">{{(state.mailList.selected.subject) ? state.mailList.selected.subject : 'No subject'}}</p>
<p class="subject" wo-touch="state.read.toggle(false)" data-icon="&#xe016;">{{(state.mailList.selected.subject) ? state.mailList.selected.subject : 'No subject'}}</p>
<p class="date">{{state.mailList.selected.sentDate | date:'EEEE, MMM d, yyyy h:mm a'}}</p>
<div class="mail-addresses">
<p>
<label>From:</label>
<span ng-repeat="u in state.mailList.selected.from">
<span class="label" ng-class="{'label-primary': u.secure === false, 'label-primary-click': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" ng-click="invite(u)" popover="#fingerprint-info">{{u.name || u.address}}</span>
<span class="label" ng-class="{'label-primary': u.secure === false, 'label-primary-click': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" wo-touch="invite(u)" popover="#fingerprint-info">{{u.name || u.address}}</span>
</span>
</p>
<p>
<label>To:</label>
<span ng-repeat="u in state.mailList.selected.to">
<span class="label" ng-class="{'label-primary': u.secure === false, 'label-primary-click': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" ng-click="invite(u)" popover="#fingerprint-info">{{u.name || u.address}}</span>
<span class="label" ng-class="{'label-primary': u.secure === false, 'label-primary-click': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" wo-touch="invite(u)" popover="#fingerprint-info">{{u.name || u.address}}</span>
</span>
</p>
<p ng-show="state.mailList.selected.cc && state.mailList.selected.cc.length > 0">
<label>Cc:</label>
<span ng-repeat="u in state.mailList.selected.cc">
<span class="label" ng-class="{'label-primary': u.secure === false, 'label-primary-click': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" ng-click="invite(u)" popover="#fingerprint-info">{{u.name || u.address}}</span>
<span class="label" ng-class="{'label-primary': u.secure === false, 'label-primary-click': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : ''}}" ng-mouseover="getKeyId(u.address)" wo-touch="invite(u)" popover="#fingerprint-info">{{u.name || u.address}}</span>
</span>
</p>
</div><!--/.mail-addresses-->
@ -36,7 +36,7 @@
<div class="attachments" ng-switch-when="true">
<span class="attachment"
ng-repeat="attachment in state.mailList.selected.attachments"
ng-click="download(attachment)">
wo-touch="download(attachment)">
<span data-icon="&#xe003;"></span>
{{attachment.filename}}
</span><!--/.attachment-->
@ -54,7 +54,7 @@
</div><!--/.working-wrapper-->
<div class="display-images">
<a ng-show="html && showImageButton" href='#' ng-click="displayImages(); $event.preventDefault()">Display images</a>
<a ng-show="html && showImageButton" href='#' wo-touch="displayImages(); $event.preventDefault()">Display images</a>
</div>
<!-- Render html body in sandboxed iframe -->
@ -81,9 +81,9 @@
<div class="reply-selection popover bottom">
<div class="arrow"></div>
<ul class="popover-content">
<li><button data-icon="&#xe014;" ng-click="state.writer.write(state.mailList.selected)">Reply</button></li>
<li><button data-icon="&#xe013;" ng-click="state.writer.write(state.mailList.selected, true)">Reply All</button></li>
<li><button data-icon="&#xe015;" ng-click="state.writer.write(state.mailList.selected, null, true)">Forward</button></li>
<li><button data-icon="&#xe014;" wo-touch="state.writer.write(state.mailList.selected)">Reply</button></li>
<li><button data-icon="&#xe013;" wo-touch="state.writer.write(state.mailList.selected, true)">Reply All</button></li>
<li><button data-icon="&#xe015;" wo-touch="state.writer.write(state.mailList.selected, null, true)">Forward</button></li>
</ul>
</div><!--/.reply-selection-->

View File

@ -1,7 +1,7 @@
<div class="lightbox-body" ng-controller="SetPassphraseCtrl">
<header>
<h2>Set passphrase</h2>
<button class="close" ng-click="state.setPassphrase.toggle(false)" data-action="lightbox-close">&#xe007;</button>
<button class="close" wo-touch="state.setPassphrase.toggle(false)" data-action="lightbox-close">&#xe007;</button>
</header>
<div class="content">
@ -25,7 +25,7 @@
</table>
<div class="control">
<button ng-click="setPassphrase()" class="btn" ng-disabled="(confirmation || newPassphrase) && confirmation !== newPassphrase" tabindex="4">Set passphrase</button>
<button wo-touch="setPassphrase()" class="btn" ng-disabled="(confirmation || newPassphrase) && confirmation !== newPassphrase" tabindex="4">Set passphrase</button>
</div>
</div><!-- /.view-set-passphrase -->

View File

@ -1,15 +1,15 @@
<div class="lightbox-body" ng-controller="WriteCtrl">
<header>
<h2>{{writerTitle}}</h2>
<button class="close" ng-click="state.writer.close()" data-action="lightbox-close">&#xe007;</button>
<button class="close" wo-touch="state.writer.close()" data-action="lightbox-close">&#xe007;</button>
</header>
<div class="content">
<div class="view-write">
<div class="mail-addresses">
<div class="mail-addresses-more">
<button ng-click="showCC = true;" ng-hide="showCC">Cc</button>
<button ng-click="showBCC = true;" ng-hide="showBCC">Bcc</button>
<button wo-touch="showCC = true;" ng-hide="showCC">Cc</button>
<button wo-touch="showBCC = true;" ng-hide="showBCC">Bcc</button>
</div>
<p field="to">
<label>To:</label>
@ -41,7 +41,7 @@
<span ng-repeat="attachment in attachments" class="attachment">
<span data-icon="&#xe003;"></span>
{{attachment.filename}}
<span class="close" data-icon="&#xe000;" ng-click="remove(attachment)"></span>
<span class="close" data-icon="&#xe000;" wo-touch="remove(attachment)"></span>
</span><!--/.attachment-->
</div><!--/.attachments-box-->
@ -54,7 +54,7 @@
</div><!--/.body-->
<div class="send-control">
<button ng-click="sendToOutbox()" class="btn" ng-class="{'btn-primary': sendBtnSecure === false}" ng-disabled="!okToSend" tabindex="4">{{sendBtnText || 'Send'}}</button>
<button wo-touch="sendToOutbox()" class="btn" ng-class="{'btn-primary': sendBtnSecure === false}" ng-disabled="!okToSend" tabindex="4">{{sendBtnText || 'Send'}}</button>
</div>
</div><!--/.write-view-->