(js) Review Mail module to decrease watchers

This commit is contained in:
Francis Lachapelle
2017-05-18 15:31:38 -04:00
parent 083be7e89f
commit 28ae2fd58a
13 changed files with 1017 additions and 524 deletions

View File

@@ -7,19 +7,20 @@
<!-- in virtual mailbox mode -->
<md-toolbar class="md-whiteframe-z1 md-hue-3"
ng-hide="!app.showingAdvancedSearch || mailbox.mode.multiple">
ng-hide="!mailbox.service.$virtualPath || mailbox.mode.multiple">
<div class="md-toolbar-tools">
<md-input-container class="md-flex">
<label><var:string label:value="Search messages in"/></label>
<md-select ng-model="app.search.mailbox">
<md-select ng-model="mailbox.service.$virtualPath">
<md-option ng-value="">
<span>{{app.accounts[0].name}}</span>
<span ng-bind="app.accounts[0].name"><!-- main account name --></span>
</md-option>
<md-option ng-repeat="folder in
app.accounts[0].$flattenMailboxes()
track by folder.path"
ng-value="folder.path">
<span ng-class="'sg-child-level-' + folder.level">{{folder.$displayName}}</span>
<span ng-class="'sg-child-level-' + folder.level"
ng-bind="folder.$displayName"><!-- mailbox name --></span>
</md-option>
</md-select>
</md-input-container>
@@ -38,13 +39,15 @@
<md-menu-divider> <!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-click="app.search.match='AND'">
<md-icon ng-class="{ 'icon-check': app.search.match == 'AND'}">
<md-icon ng-class="{ 'icon-check': app.search.match == 'AND'}"
label:aria-label="Match all of the following">
<!-- all --></md-icon><var:string label:value="Match all of the following"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="app.search.match='OR'">
<md-icon ng-class="{ 'icon-check': app.search.match == 'OR'}">
<md-icon ng-class="{ 'icon-check': app.search.match == 'OR'}"
label:aria-label="Match any of the following">
<!-- any --></md-icon><var:string label:value="Match any of the following"/>
</md-button>
</md-menu-item>
@@ -61,7 +64,7 @@
</md-toolbar>
<!-- single-selection toolbars -->
<md-toolbar class="md-accent md-hue-1"
ng-hide="app.showingAdvancedSearch || mailbox.mode.multiple">
ng-hide="mailbox.service.$virtualPath || mailbox.mode.multiple">
<!-- sort mode (default) -->
<div class="md-toolbar-tools" ng-hide="mailbox.mode.search">
<md-button class="sg-icon-button" label:aria-label="Search"
@@ -69,7 +72,7 @@
<md-icon>search</md-icon>
</md-button>
<a href="javascript:void(0)" class="sg-folder-name"
ng-click="mailbox.searchMode()">{{mailbox.selectedFolder.$displayName}}</a>
ng-click="mailbox.searchMode()" ng-bind="mailbox.selectedFolder.$displayName"><!-- mailbox name --></a>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Sort"
ng-click="$mdMenu.open()">
@@ -78,31 +81,36 @@
<md-menu-content>
<md-menu-item>
<md-button ng-click="mailbox.sort('subject')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('subject') }">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('subject') }"
label:aria-label="Subject">
<!-- subject --></md-icon> <var:string label:value="Subject"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('from')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('from') }">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('from') }"
label:aria-label="From">
<!-- from --></md-icon> <var:string label:value="From"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('date')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('date') }">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('date') }"
label:aria-label="Date">
<!-- date --></md-icon> <var:string label:value="Date"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('size')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('size') }">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('size') }"
label:aria-label="Size">
<!-- size --></md-icon> <var:string label:value="Size"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('arrival')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('arrival') }">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('arrival') }"
label:aria-label="Order Received">
<!-- order received --></md-icon> <var:string label:value="Order Received"/>
</md-button>
</md-menu-item>
@@ -158,7 +166,7 @@
<md-button class="sg-icon-button" ng-click="mailbox.unselectMessages()">
<md-icon>arrow_back</md-icon>
</md-button>
<label>{{mailbox.service.selectedFolder.$selectedCount()}} <var:string label:value="selected"/></label>
<label><span ng-bind="mailbox.service.selectedFolder.$selectedCount()"><!-- count --></span> <var:string label:value="selected"/></label>
<div class="md-flex"><!-- spacer --></div>
<md-button class="sg-icon-button" ng-click="mailbox.selectAll()">
<md-tooltip md-direction="bottom"><var:string label:value="Select All"/></md-tooltip>
@@ -168,8 +176,8 @@
<md-icon>delete</md-icon>
</md-button>
<md-button class="sg-icon-button" ng-click="mailbox.markOrUnMarkMessagesAsJunk()">
<md-icon ng-hide="mailbox.service.selectedFolder.type == 'junk'">thumb_down</md-icon>
<md-icon ng-hide="mailbox.service.selectedFolder.type != 'junk'">thumb_up</md-icon>
<md-icon ng-hide="::mailbox.service.selectedFolder.type == 'junk'">thumb_down</md-icon>
<md-icon ng-hide="::mailbox.service.selectedFolder.type != 'junk'">thumb_up</md-icon>
</md-button>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="More messages options" ng-click="$mdMenu.open()">
@@ -202,19 +210,22 @@
<var:string label:value="Copy To"/>
</md-button>
<md-menu-content width="4">
<div ng-repeat="account in mailbox.accounts track by account.id">
<div ng-repeat="account in ::mailbox.accounts track by account.id">
<md-menu-item>
<md-menu>
<md-button class="md-primary" ng-click="$mdMenu.open($event)">{{account.name}}</md-button>
<md-button class="md-primary" ng-click="$mdMenu.open($event)"
ng-bind="::account.name"><!-- account name --></md-button>
<md-menu-content class="md-dense" width="4">
<div ng-repeat="folder in
account.$flattenMailboxes({ all: true })
track by folder.path">
<md-menu-item>
<md-button class="sg-no-wrap"
ng-disabled="mailbox.service.selectedFolder.id == folder.id"
aria-label="{{folder.$displayName}}"
ng-disabled="::(mailbox.service.selectedFolder.id == folder.id)"
ng-click="mailbox.copySelectedMessages(folder.id)">
<span ng-class="'sg-child-level-' + folder.level">{{folder.$displayName}}</span>
<span ng-class="::('sg-child-level-' + folder.level)"
ng-bind="folder.$displayName"><!-- mailbox name --></span>
</md-button>
</md-menu-item>
</div>
@@ -231,19 +242,22 @@
<var:string label:value="Move To"/>
</md-button>
<md-menu-content width="4">
<div ng-repeat="account in mailbox.accounts track by account.id">
<div ng-repeat="account in ::mailbox.accounts track by account.id">
<md-menu-item>
<md-menu>
<md-button class="md-primary" ng-click="$mdMenu.open($event)">{{account.name}}</md-button>
<md-button class="md-primary" ng-click="$mdMenu.open($event)"
ng-bind="::account.name"><!-- account name --></md-button>
<md-menu-content class="md-dense" width="4">
<div ng-repeat="folder in
account.$flattenMailboxes({ all: true })
track by folder.path">
<md-menu-item>
<md-button class="sg-no-wrap"
ng-disabled="mailbox.service.selectedFolder.id == folder.id"
aria-label="{{folder.$displayName}}"
ng-disabled="::(mailbox.service.selectedFolder.id == folder.id)"
ng-click="mailbox.moveSelectedMessages(folder.id)">
<span ng-class="'sg-child-level-' + folder.level">{{folder.$displayName}}</span>
<span ng-class="::('sg-child-level-' + folder.level)"
ng-bind="folder.$displayName"><!-- mailbox name --></span>
</md-button>
</md-menu-item>
</div>
@@ -266,7 +280,7 @@
<!-- message count -->
<span ng-switch="mailbox.service.selectedFolder.getLength()">
<span ng-switch-when="0"><var:string label:value="No message"/></span>
<span ng-switch-default="true">{{mailbox.service.selectedFolder.getLength()}} <var:string label:value="messages"/></span>
<span ng-switch-default="true"><span ng-bind="mailbox.service.selectedFolder.getLength()"><!-- count --></span> <var:string label:value="messages"/></span>
</span>
</md-subheader>
<md-virtual-repeat-container class="md-flex" md-top-index="mailbox.selectedFolder.$topIndex">
@@ -277,11 +291,12 @@
sg-drag-count="mailbox.selectedFolder.$selectedCount()">
<md-list-item
aria-label="{{currentMessage.subject}}"
ng-class="{'md-default-theme md-accent md-bg md-hue-2': mailbox.selectedFolder.isSelectedMessage(currentMessage.uid, currentMessage.$mailbox.path),
unread: !currentMessage.isread}"
class="sg-message-list-item"
ng-class="{'md-default-theme md-accent md-bg md-hue-2': mailbox.selectedFolder.isSelectedMessage(currentMessage.uid, currentMessage.$mailbox.path)}"
md-virtual-repeat="currentMessage in mailbox.service.selectedFolder"
md-on-demand="md-on-demand" md-item-size="56"
ng-click="mailbox.selectMessage(currentMessage)">
ng-click="mailbox.selectMessage(currentMessage)"
sg-message="currentMessage">
<div class="md-secondary sg-avatar-selectable"
label:aria-label="Select Message"
ng-class="{ 'sg-avatar-selected': currentMessage.selected }"
@@ -290,37 +305,8 @@
sg-email="mailbox.service.selectedFolder.type == 'sent' ? currentMessage.to[0].email : currentMessage.from[0].email"
size="40">person</sg-avatar-image>
</div>
<div class="sg-category"
ng-repeat="tag in currentMessage.flags | limitTo:5"
ng-style="{ 'background-color': currentMessage.constructor.$tags[tag][1], left: ($index * 3) + 'px' }"><!-- calendar color --></div>
<div class="sg-tile-content">
<div class="sg-md-subhead">
<div>
<span class="sg-label-outline ng-hide"
ng-show="mailbox.service.$virtualMode">{{currentMessage.$mailbox.$displayName}}</span>
<md-icon class="ng-hide"
ng-show="currentMessage.priority.level == 1 ||
currentMessage.priority.level == 2"
ng-class="{'md-warn': currentMessage.priority.level == 1}">error</md-icon>
{{mailbox.service.selectedFolder.type == 'sent' ? currentMessage.$shortAddress('to' ) : currentMessage.$shortAddress('from' )}}
</div>
<div class="sg-tile-date" ng-bind="currentMessage.relativedate"><!-- date --></div>
</div>
<div class="sg-md-body">
<div>{{currentMessage.subject}}</div>
<div class="sg-tile-size" ng-bind="currentMessage.size"><!-- size --></div>
</div>
</div>
<div class="sg-tile-icons">
<md-icon class="ng-hide" ng-show="currentMessage.isflagged">star</md-icon>
<md-icon class="ng-hide" ng-show="currentMessage.isanswered">reply</md-icon>
<md-icon class="ng-hide" ng-show="currentMessage.isforwarded">forward</md-icon>
<md-icon class="ng-hide" ng-show="currentMessage.hasattachment">attach_file</md-icon>
</div>
<div class="sg-progress-linear-bottom">
<md-progress-linear class="md-accent"
md-mode="indeterminate"
ng-disabled="!currentMessage.$isLoading()"><!-- message loading progress --></md-progress-linear>
<div class="md-list-item-inner sg-message-list-item-main">
<!-- sgMessageListItemMain directive -->
</div>
</md-list-item>
</md-list>

View File

@@ -34,26 +34,28 @@
<var:component className="UIxSidenavToolbarTemplate" />
<md-content class="md-flex" layout="column" md-scroll-y="md-scroll-y"
md-colors="::{ backgroundColor: 'default-background-300' }">
<section layout="column"
<section class="sg-account-section"
layout="column"
ng-repeat="account in ::app.accounts track by account.id"
ng-class="{ 'md-flex': account.$expanded }">
<md-list>
<md-list-item aria-label="{{ ::'Toggle visibility' | loc }}"
ng-click="app.toggleAccountState(account)">
<div class="sg-no-wrap">{{account.name}}</div>
<md-list-item ng-click="app.toggleAccountState(account)">
<div class="sg-no-wrap"
aria-label="{{ ::'Toggle visibility' | loc }}"
ng-bind="::account.name"><!-- account name --></div>
<md-menu class="md-secondary">
<md-icon label:aria-label="Options"
ng-click="$mdMenu.open($event)"
md-menu-origin="md-menu-origin">more_vert</md-icon>
<md-menu-content width="3">
<md-menu-item ng-show="account.id == 0">
<md-menu-item ng-show="::account.id == 0">
<md-button
label:aria-label="Delegation..."
ng-click="app.delegate(account)">
<var:string label:value="Delegation..."/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="app.showSubscribedOnly == 1">
<md-menu-item ng-show="::app.showSubscribedOnly == 1">
<md-button
label:aria-label="Subscribe..."
ng-click="app.subscribe(account)">
@@ -71,7 +73,7 @@
</md-menu>
</md-list-item>
</md-list>
<div class="sg-quota ng-hide" ng-show="account.$quota">
<div class="sg-quota ng-hide" ng-show="::account.$quota">
<md-progress-linear md-mode="determinate"
ng-class="{ 'md-warn': account.$quota.percent > 70 }"
value="{{account.$quota.percent}}"><!-- quota --></md-progress-linear>
@@ -81,115 +83,14 @@
</div>
<md-virtual-repeat-container ng-class="{ 'md-flex': account.$expanded }">
<md-list>
<md-list-item md-virtual-repeat="folder in account" md-item-size="48" md-on-demand="md-on-demand"
class="md-clickable md-default-theme md-background md-hue-1"
ng-class="{'md-bg': folder.id == app.service.selectedFolder.id}"
sg-droppable="app.isDroppableFolder(dragFolder, folder)"
sg-drop="app.dragSelectedMessages(dragFolder, folder, dragMode)">
<div class="sg-child-level-0"
ng-class="'sg-child-level-' + folder.level">
<md-checkbox class="sg-folder"
ng-class="folder.$icon"
label:aria-label="Expanded"
ng-model="folder.$expanded"
ng-disabled="folder.children.length == 0"
ng-change="account.$flattenMailboxes({ reload: true, saveState: true })">
<md-icon>{{folder.$icon}}</md-icon></md-checkbox>
</div>
<p class="sg-item-name ng-hide"
ng-click="app.selectFolder($event, account, folder)"
ng-dblclick="app.editFolder(folder)"
ng-show="app.editMode != folder.path">
{{folder.$displayName}}
<span class="sg-counter-badge ng-hide" ng-show="folder.unseenCount">{{folder.unseenCount}}</span>
</p>
<md-input-container class="md-flex ng-hide"
ng-show="app.editMode == folder.path">
<input class="sg-item-name" type="text"
label:aria-label="Enter the new name of your folder"
ng-model="folder.name"
ng-blur="app.saveFolder(folder)"
sg-focus-on="mailboxName_{{folder.path}}"
sg-enter="app.saveFolder(folder)"
sg-escape="app.revertEditing(folder)"/>
</md-input-container>
<md-menu class="ng-hide"
ng-show="app.service.selectedFolder.id == folder.id">
<md-icon label:aria-label="Options"
ng-click="$mdMenu.open($event)"
md-menu-origin="md-menu-origin">more_vert</md-icon>
<md-menu-content width="3">
<md-menu-item>
<md-button type="button" md-menu-align-target="md-menu-align-target"
ng-click="app.markFolderRead(folder)">
<var:string label:value="Mark Folder Read"/>
</md-button>
</md-menu-item>
<md-menu-item ng-hide="folder.$isNoInferiors">
<md-button type="button" ng-click="app.newFolder(folder)">
<var:string label:value="New Subfolder..."/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="folder.$isEditable">
<md-button type="button" ng-click="app.editFolder(folder)">
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="app.compactFolder(folder)">
<var:string label:value="Compact"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="folder.$isEditable">
<md-button type="button" ng-click="app.confirmDelete(folder)">
<var:string label:value="Delete"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="folder.type == 'trash'">
<md-button type="button" ng-click="app.emptyTrashFolder(folder)">
<var:string label:value="Empty Trash"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="folder.exportFolder()">
<var:string label:value="Export"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button"
ng-click="app.showAdvancedSearch(folder.path)">
<var:string label:value="Search"/>
</md-button>
</md-menu-item>
<md-menu-divider ng-show="folder.$canFolderAs()"><!-- divider --></md-menu-divider>
<md-menu-item ng-show="folder.type == 'folder'">
<md-button type="button" ng-click="app.setFolderAs(folder, 'Drafts')">
<var:string label:value="Set as Drafts"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="folder.$canFolderAs()">
<md-button type="button" ng-click="app.setFolderAs(folder, 'Sent')">
<var:string label:value="Set as Sent"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="folder.$canFolderAs()">
<md-button type="button" ng-click="app.setFolderAs(folder, 'Trash')">
<var:string label:value="Set as Trash"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="folder.$canFolderAs()">
<md-button type="button" ng-click="app.setFolderAs(folder, 'Junk')">
<var:string label:value="Set as Junk"/>
</md-button>
</md-menu-item>
<md-menu-divider ng-show="folder.type != 'additional'"><!-- divider --></md-menu-divider>
<md-menu-item ng-show="folder.type != 'additional'">
<md-button type="button" ng-click="app.share(folder)">
<var:string label:value="Sharing..."/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-list-item
class="sg-mailbox-list-item md-clickable md-default-theme md-background md-hue-1"
ng-class="{'md-bg sg-selected': folder.id == app.service.selectedFolder.id}"
md-virtual-repeat="folder in account" md-item-size="48" md-on-demand="md-on-demand"
sg-mailbox="folder"
sg-droppable="app.isDroppableFolder(dragFolder, folder)"
sg-drop="app.dragSelectedMessages(dragFolder, folder, dragMode)">
<!-- sgMailboxListItem directive -->
</md-list-item>
</md-list>
</md-virtual-repeat-container>
@@ -204,7 +105,7 @@
</md-toolbar>
<md-content class="md-flex"
md-colors="::{backgroundColor: 'default-background-200'}"
layout="column" layout-align="center center" layout-fill="layout-fill">
layout="column" layout-align="center center">
<div class="sg-md-title"
md-colors="::{color: 'default-background-500'}">
<var:string label:value="No mailbox selected"/>
@@ -215,13 +116,13 @@
<script type="text/ng-template" id="UIxMailFolderTemplate">
<md-toolbar layout="row" layout-align="space-between center" class="toolbar-main"
ng-hide="app.showingAdvancedSearch">
ng-hide="mailbox.service.$virtualPath">
<var:component className="UIxTopnavToolbar"/>
</md-toolbar>
<!-- Advanced search toolbar -->
<md-toolbar layout="column" class="md-tall toolbar-main md-hue-3"
ng-show="app.showingAdvancedSearch">
ng-show="mailbox.service.$virtualPath">
<div class="md-toolbar-tools">
<div layout="column" class="md-flex">
<div class="pseudo-input-container--compact">
@@ -261,8 +162,8 @@
<md-chip-template>
<span class="md-caption" ng-show="$chip.negative == 0">(<var:string label:value="match"/></span>
<span class="md-caption" ng-show="$chip.negative == 1">(<var:string label:value="does not match"/></span>
<span class="md-caption">{{$chip.searchBy}})</span>
<span>{{$chip.searchInput}}</span>
<span class="md-caption" ng-bind="$chip.searchBy"><!-- search by --></span>
<span ng-bind="$chip.searchInput"><!-- search input --></span>
</md-chip-template>
</md-chips>
</div>
@@ -273,11 +174,88 @@
</div>
</script>
<!-- modal for mailbox sharing options -->
<!-- template of contextual menu for a mailbox -->
<script type="text/ng-template" id="UIxMailFolderMenu">
<div md-whiteframe="3">
<md-menu-content width="3">
<md-menu-item>
<md-button type="button" md-menu-align-target="md-menu-align-target"
ng-click="$menuCtrl.markFolderRead()">
<var:string label:value="Mark Folder Read"/>
</md-button>
</md-menu-item>
<md-menu-item ng-hide="::$menuCtrl.folder.$isNoInferiors">
<md-button type="button" ng-click="$menuCtrl.newFolder()">
<var:string label:value="New Subfolder..."/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="::$menuCtrl.folder.$isEditable">
<md-button type="button" ng-click="$menuCtrl.editFolder()">
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="$menuCtrl.compactFolder()">
<var:string label:value="Compact"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="::$menuCtrl.folder.$isEditable">
<md-button type="button" ng-click="$menuCtrl.confirmDelete()">
<var:string label:value="Delete"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="::($menuCtrl.folder.type == 'trash')">
<md-button type="button" ng-click="$menuCtrl.emptyTrashFolder()">
<var:string label:value="Empty Trash"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="$menuCtrl.folder.exportFolder()">
<var:string label:value="Export"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="$menuCtrl.showAdvancedSearch()">
<var:string label:value="Search"/>
</md-button>
</md-menu-item>
<md-menu-divider ng-show="::$menuCtrl.folder.$canFolderAs()"><!-- divider --></md-menu-divider>
<md-menu-item ng-show="::$menuCtrl.folder.$canFolderAs()">
<md-button type="button" ng-click="$menuCtrl.setFolderAs('Drafts')">
<var:string label:value="Set as Drafts"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="::$menuCtrl.folder.$canFolderAs()">
<md-button type="button" ng-click="$menuCtrl.setFolderAs('Sent')">
<var:string label:value="Set as Sent"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="::$menuCtrl.folder.$canFolderAs()">
<md-button type="button" ng-click="$menuCtrl.setFolderAs('Trash')">
<var:string label:value="Set as Trash"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="::$menuCtrl.folder.$canFolderAs()">
<md-button type="button" ng-click="$menuCtrl.setFolderAs('Junk')">
<var:string label:value="Set as Junk"/>
</md-button>
</md-menu-item>
<md-menu-divider ng-show="::($menuCtrl.folder.type != 'additional')"><!-- divider --></md-menu-divider>
<md-menu-item ng-show="::($menuCtrl.folder.type != 'additional')">
<md-button type="button" ng-click="$menuCtrl.share()">
<var:string label:value="Sharing..."/>
</md-button>
</md-menu-item>
</md-menu-content>
</div>
</script>
<!-- template of modal for mailbox sharing options -->
<script type="text/ng-template" id="UIxUserRightsEditor">
<var:component className="UIxMailUserRightsEditor" />
</script>
<!-- template of mail viewer -->
<script type="text/ng-template" id="UIxMailViewTemplate">
<var:component className="UIxMailViewTemplate" />
</script>

View File

@@ -14,12 +14,12 @@
<md-button ng-click="toggleCenter()"
class="md-icon-button md-primary md-hue-1 hide show-gt-xs"
aria-hidden="true"
ng-if="!isPopup">
ng-if="::!isPopup">
<md-icon class="icon-fullscreen"
ng-class="{ 'icon-fullscreen-exit': centerIsClose }"><!-- fullscreen --></md-icon>
</md-button>
<md-button class="md-icon-button"
ng-if="isPopup"
ng-if="::isPopup"
label:aria-label="Close"
ng-click="viewer.closePopup()">
<md-icon>close</md-icon>
@@ -36,7 +36,7 @@
'icon-star-border': !viewer.message.isflagged}"><!-- flag --></md-icon>
</md-button>
<md-button class="sg-icon-button"
ng-hide="viewer.message.isDraft"
ng-hide="::viewer.message.isDraft"
ng-click="viewer.reply($event)"
label:aria-label="Reply">
<md-tooltip md-direction="bottom"><var:string label:value="Reply to Sender Only"/></md-tooltip>
@@ -50,13 +50,13 @@
<md-icon>reply_all</md-icon>
</md-button>
<md-button class="sg-icon-button" label:aria-label="Forward"
ng-hide="viewer.message.isDraft"
ng-hide="::viewer.message.isDraft"
ng-click="viewer.forward($event)">
<md-tooltip md-direction="bottom"><var:string label:value="Forward selected message"/></md-tooltip>
<md-icon>forward</md-icon>
</md-button>
<md-button class="sg-icon-button" label:aria-label="Edit"
ng-show="viewer.message.isDraft"
ng-show="::viewer.message.isDraft"
ng-click="viewer.edit($event)">
<md-icon>create</md-icon>
</md-button>
@@ -66,7 +66,7 @@
<md-icon>delete</md-icon>
</md-button>
<md-button class="sg-icon-button hide show-gt-md" label:aria-label="Open in New Mail Window"
ng-hide="isPopup"
ng-hide="::isPopup"
ng-click="viewer.openPopup()">
<md-tooltip md-direction="bottom"><var:string label:value="Open in New Mail Window"/></md-tooltip>
<md-icon>open_in_new</md-icon>
@@ -124,20 +124,20 @@
</md-card-actions>
<md-card-content>
<div class="sg-padded">
<h5>{{viewer.message.subject}}</h5>
<time class="msg-date" datetime="viewer.message.date" ng-bind="viewer.message.date"><!-- date --></time>
<h5 ng-bind="::viewer.message.subject"><!-- subject --></h5>
<time class="msg-date" datetime="viewer.message.date" ng-bind="::viewer.message.date"><!-- date --></time>
</div>
<div>
<div layout="row" layout-wrap="layout-wrap">
<div class="pseudo-input-container--compact" flex="50" flex-xs="100">
<div layout="row" layout-align="start center">
<sg-avatar-image class="md-tile-left"
sg-email="viewer.message.from[0].email"
sg-email="::viewer.message.from[0].email"
size="40">person</sg-avatar-image>
<div class="md-list-item-text">
<span>{{ viewer.message.from[0].name }}</span><br/>
<span ng-bind="::viewer.message.from[0].name"><!-- from --></span><br/>
<a href="#" class="md-caption"
ng-bind="viewer.message.from[0].email"
ng-bind="::viewer.message.from[0].email"
ng-click="viewer.newMessage($event, { to: [viewer.message.from[0].full] })"><!-- from --></a>
</div>
</div>
@@ -149,22 +149,23 @@
</label>
<div class="pseudo-input-field"
ng-hide="viewer.$showDetailedRecipients">
<a href="#" ng-click="viewer.toggleDetailedRecipients($event)">{{viewer.message.$shortRecipients(5)}}</a>
<a href="#" ng-click="viewer.toggleDetailedRecipients($event)"
ng-bind="::viewer.message.$shortRecipients(5)"><!-- to --></a>
</div>
<div class="pseudo-input-field" ng-show="viewer.$showDetailedRecipients">
<span ng-repeat="recipient in viewer.message.to">
<a href="#" ng-bind="recipient.full"
<a href="#" ng-bind="::recipient.full"
ng-click="viewer.newMessage($event, { to: [recipient.full] })"><!-- recipient --></a>
</span>
</div>
</div>
<div class="pseudo-input-container--compact" ng-show="viewer.$showDetailedRecipients">
<label class="pseudo-input-label" ng-show="viewer.message.cc.length > 0">
<label class="pseudo-input-label" ng-show="::viewer.message.cc.length > 0">
<var:string label:value="Cc"/>
</label>
<div class="pseudo-input-field">
<span ng-repeat="recipient in viewer.message.cc">
<a href="#" ng-bind="recipient.full"
<span ng-repeat="recipient in ::viewer.message.cc">
<a href="#" ng-bind="::recipient.full"
ng-click="viewer.newMessage($event, { to: [recipient.full] })"><!-- recipient --></a>
</span>
<md-button style="float: right"
@@ -184,7 +185,7 @@
<span class="sg-chip-color">
<span ng-style="{ 'background-color': viewer.service.$tags[$chip][1] }"><!-- color --></span>
</span>
<span>{{viewer.service.$tags[$chip][0] || $chip}}</span>
<span ng-bind="viewer.service.$tags[$chip][0] || $chip"><!-- tag --></span>
</md-chip-template>
<md-autocomplete
md-search-text="viewer.tags.searchText"
@@ -196,7 +197,8 @@
<div class="sg-color-chip"
ng-style="{'background-color': tag.color}"><!-- color --></div>
<div md-highlight-text="viewer.tags.searchText"
md-highlight-flags="^i">{{tag.description}}</div>
md-highlight-flags="^i"
ng-bind="tag.description"><!-- description --></div>
</div>
</md-item-template>
</md-autocomplete>
@@ -256,14 +258,14 @@
<div layout="row" layout-wrap="layout-wrap">
<div class="mailer_mailcontent" layout="row" layout-wrap="layout-wrap"
ng-repeat="part in viewer.message.$content()"
ng-class="part.msgclass">
<div class="md-flex"
ng-class="::part.msgclass">
<div class="md-flex sg-mail-part"
tabindex="-1"
ng-if="part.html"
ng-if="::part.html"
ng-click="viewer.filterMailtoLinks($event)"
ng-bind-html="part.content | ensureTarget"><!-- html msg --></div>
<div class="md-flex"
ng-if="part.compile"
<div class="md-flex sg-mail-part"
ng-if="::part.compile"
sg-compile="part.content"
sg-zoomable-image="sg-zoomable-image"><!-- angular-friendly msg --></div>
</div>

View File

@@ -9,6 +9,27 @@ String.prototype.startsWith = function(pattern, position) {
return this.lastIndexOf(pattern, position) === position;
};
// See ngSanitize
String.prototype.encodeEntities = function () {
// Regular Expressions for parsing tags and attributes
var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
// Match everything outside of normal chars and " (quote character)
NON_ALPHANUMERIC_REGEXP = /([^#-~ |!])/g;
return this.
replace(/&/g, '&amp;').
replace(SURROGATE_PAIR_REGEXP, function(value) {
var hi = value.charCodeAt(0);
var low = value.charCodeAt(1);
return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
}).
replace(NON_ALPHANUMERIC_REGEXP, function(value) {
return '&#' + value.charCodeAt(0) + ';';
}).
replace(/</g, '&lt;').
replace(/>/g, '&gt;');
};
String.prototype._base64_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
String.prototype.base64encode = function () {
var output = "";

View File

@@ -44,6 +44,7 @@
selectedFolder: null,
$refreshTimeout: null,
$virtualMode: false,
$virtualPath: false,
PRELOAD: PRELOAD
});
// Initialize sort parameters from user's settings
@@ -476,6 +477,16 @@
return this.flags.indexOf('noselect') >= 0;
};
/**
* @function getClassName
* @memberof Mailbox.prototype
* @desc Not used but defined because it is called from UIxAclEditor.wox.
* @returns a string representing the foreground CSS class name
*/
Mailbox.prototype.getClassName = function(base) {
return false;
};
/**
* @function $rename
* @memberof AddressBook.prototype
@@ -623,7 +634,14 @@
* @returns a promise of the HTTP operation
*/
Mailbox.prototype.$markAsRead = function() {
return Mailbox.$$resource.post(this.id, 'markRead');
var _this = this;
return Mailbox.$$resource.post(this.id, 'markRead').then(function() {
_this.unseenCount = 0;
_.forEach(_this.$messages, function(message) {
message.isread = true;
});
});
};
/**
@@ -931,6 +949,7 @@
}, function(data) {
angular.extend(_this, data);
_this.isError = true;
_this.$isLoading = false;
deferred.reject();
});

View File

@@ -12,85 +12,68 @@
defaultWindowTitle = angular.element($window.document).find('title').attr('sg-default') || "SOGo",
hotkeys = [];
// Expose controller for eventual popup windows
$window.$mailboxController = vm;
this.$onInit = function() {
// Expose controller for eventual popup windows
$window.$mailboxController = vm;
vm.service = Mailbox;
vm.accounts = stateAccounts;
vm.account = stateAccount;
vm.selectedFolder = stateMailbox;
vm.selectMessage = selectMessage;
vm.messageDialog = null; // also access from Message controller
vm.toggleMessageSelection = toggleMessageSelection;
vm.sort = sort;
vm.sortedBy = sortedBy;
vm.searchMode = searchMode;
vm.cancelSearch = cancelSearch;
vm.newMessage = newMessage;
vm.mode = { search: false, multiple: 0 };
vm.confirmDeleteSelectedMessages = confirmDeleteSelectedMessages;
vm.markOrUnMarkMessagesAsJunk = markOrUnMarkMessagesAsJunk;
vm.copySelectedMessages = copySelectedMessages;
vm.moveSelectedMessages = moveSelectedMessages;
vm.markSelectedMessagesAsFlagged = markSelectedMessagesAsFlagged;
vm.markSelectedMessagesAsUnread = markSelectedMessagesAsUnread;
vm.markSelectedMessagesAsRead = markSelectedMessagesAsRead;
vm.selectAll = selectAll;
vm.unselectMessages = unselectMessages;
this.service = Mailbox;
this.accounts = stateAccounts;
this.account = stateAccount;
this.selectedFolder = stateMailbox;
this.messageDialog = null; // also access from Message controller
this.mode = { search: false, multiple: 0 };
_registerHotkeys(hotkeys);
stateMailbox.selectFolder();
_registerHotkeys(hotkeys);
// Expunge mailbox when leaving the Mail module
angular.element($window).on('beforeunload', _compactBeforeUnload);
$scope.$on('$destroy', function() {
angular.element($window).off('beforeunload', _compactBeforeUnload);
// Deregister hotkeys
_.forEach(hotkeys, function(key) {
sgHotkeys.deregisterHotkey(key);
// Expunge mailbox when leaving the Mail module
angular.element($window).on('beforeunload', _compactBeforeUnload);
$scope.$on('$destroy', function() {
angular.element($window).off('beforeunload', _compactBeforeUnload);
// Deregister hotkeys
_.forEach(hotkeys, function(key) {
sgHotkeys.deregisterHotkey(key);
});
});
});
// Update window's title with unseen messages count of selected mailbox
$scope.$watch(function() { return vm.selectedFolder.unseenCount; }, function(unseenCount) {
var title = defaultWindowTitle + ' - ';
if (unseenCount)
title += '(' + unseenCount + ') ';
title += vm.selectedFolder.$displayName;
$window.document.title = title;
});
// Update window's title with unseen messages count of selected mailbox
$scope.$watch(function() { return vm.selectedFolder.unseenCount; }, function(unseenCount) {
var title = defaultWindowTitle + ' - ';
if (unseenCount)
title += '(' + unseenCount + ') ';
title += vm.selectedFolder.$displayName;
$window.document.title = title;
});
};
function _registerHotkeys(keys) {
keys.push(sgHotkeys.createHotkey({
key: l('hotkey_search'),
description: l('Search'),
callback: searchMode
callback: vm.searchMode
}));
keys.push(sgHotkeys.createHotkey({
key: l('hotkey_compose'),
description: l('Write a new message'),
callback: function($event) {
if (vm.messageDialog === null)
newMessage($event);
vm.newMessage($event);
}
}));
keys.push(sgHotkeys.createHotkey({
key: l('hotkey_junk'),
description: l('Mark the selected messages as junk'),
callback: markOrUnMarkMessagesAsJunk
callback: vm.markOrUnMarkMessagesAsJunk
}));
keys.push(sgHotkeys.createHotkey({
key: 'space',
description: l('Toggle item'),
callback: toggleMessageSelection
callback: vm.toggleMessageSelection
}));
keys.push(sgHotkeys.createHotkey({
key: 'shift+space',
description: l('Toggle range of items'),
callback: toggleMessageSelection
callback: vm.toggleMessageSelection
}));
keys.push(sgHotkeys.createHotkey({
key: 'up',
@@ -119,7 +102,7 @@
keys.push(sgHotkeys.createHotkey({
key: 'backspace',
description: l('Delete selected message or folder'),
callback: confirmDeleteSelectedMessages
callback: vm.confirmDeleteSelectedMessages
}));
// Register the hotkeys
@@ -132,20 +115,20 @@
return vm.selectedFolder.$compact();
}
function sort(field) {
this.sort = function(field) {
vm.selectedFolder.$filter({ sort: field });
}
};
function sortedBy(field) {
this.sortedBy = function(field) {
return Mailbox.$query.sort == field;
}
};
function searchMode() {
this.searchMode = function() {
vm.mode.search = true;
focus('search');
}
};
function cancelSearch() {
this.cancelSearch = function() {
vm.mode.search = false;
vm.selectedFolder.$filter().then(function() {
if (vm.selectedFolder.selectedMessage) {
@@ -154,9 +137,9 @@
});
}
});
}
};
function newMessage($event, inPopup) {
this.newMessage = function($event, inPopup) {
var message;
if (vm.messageDialog === null) {
@@ -183,7 +166,7 @@
});
}
}
}
};
function _newMessageInPopup() {
var url = [sgSettings.baseURL(),
@@ -227,7 +210,7 @@
}
if (index > -1)
selectMessage(vm.selectedFolder.$messages[index]);
vm.selectMessage(vm.selectedFolder.$messages[index]);
$event.preventDefault();
@@ -250,7 +233,7 @@
index = 0;
if (index < vm.selectedFolder.getLength())
selectMessage(vm.selectedFolder.$messages[index]);
vm.selectMessage(vm.selectedFolder.$messages[index]);
else
index = -1;
@@ -265,7 +248,7 @@
if (vm.selectedFolder.hasSelectedMessage()) {
index = _nextMessage($event);
if (index >= 0)
toggleMessageSelection($event, vm.selectedFolder.$messages[index]);
vm.toggleMessageSelection($event, vm.selectedFolder.$messages[index]);
}
}
@@ -275,23 +258,25 @@
if (vm.selectedFolder.hasSelectedMessage()) {
index = _previousMessage($event);
if (index >= 0)
toggleMessageSelection($event, vm.selectedFolder.$messages[index]);
vm.toggleMessageSelection($event, vm.selectedFolder.$messages[index]);
}
}
function selectMessage(message) {
this.selectMessage = function(message) {
if (Mailbox.$virtualMode)
$state.go('mail.account.virtualMailbox.message', {mailboxId: encodeUriFilter(message.$mailbox.path), messageId: message.uid});
else
$state.go('mail.account.mailbox.message', {messageId: message.uid});
}
};
function toggleMessageSelection($event, message) {
this.toggleMessageSelection = function($event, message) {
var folder = vm.selectedFolder,
selectedIndex, nextSelectedIndex, i;
if (!message)
message = folder.$selectedMessage();
if (!message)
return true;
message.selected = !message.selected;
vm.mode.multiple += message.selected? 1 : -1;
@@ -320,7 +305,7 @@
$event.preventDefault();
$event.stopPropagation();
}
};
/**
* Batch operations
@@ -372,7 +357,7 @@
}
}
function confirmDeleteSelectedMessages($event) {
this.confirmDeleteSelectedMessages = function($event) {
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (vm.messageDialog === null && _.size(selectedMessages) > 0)
@@ -417,9 +402,9 @@
});
$event.preventDefault();
}
};
function markOrUnMarkMessagesAsJunk() {
this.markOrUnMarkMessagesAsJunk = function() {
var moveSelectedMessage = vm.selectedFolder.hasSelectedMessage();
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) === 0 && moveSelectedMessage)
@@ -443,9 +428,9 @@
}
});
});
}
};
function copySelectedMessages(dstFolder) {
this.copySelectedMessages = function(dstFolder) {
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0)
vm.selectedFolder.$copyMessages(selectedMessages, '/' + dstFolder).then(function() {
@@ -455,9 +440,9 @@
.position('top right')
.hideDelay(2000));
});
}
};
function moveSelectedMessages(dstFolder) {
this.moveSelectedMessages = function(dstFolder) {
var moveSelectedMessage = vm.selectedFolder.hasSelectedMessage();
var selectedMessages = vm.selectedFolder.$selectedMessages();
var count = vm.selectedFolder.$selectedCount();
@@ -479,9 +464,9 @@
_unselectMessage(moveSelectedMessage, index);
}
});
}
};
function selectAll() {
this.selectAll = function() {
var count = 0;
_.forEach(_currentMailboxes(), function(folder) {
var i = 0, length = folder.$messages.length;
@@ -490,18 +475,18 @@
count += length;
});
vm.mode.multiple = count;
}
};
function unselectMessages() {
this.unselectMessages = function() {
_.forEach(_currentMailboxes(), function(folder) {
_.forEach(folder.$messages, function(message) {
message.selected = false;
});
});
vm.mode.multiple = 0;
}
};
function markSelectedMessagesAsFlagged() {
this.markSelectedMessagesAsFlagged = function() {
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0)
vm.selectedFolder.$flagMessages(selectedMessages, '\\Flagged', 'add').then(function(messages) {
@@ -509,9 +494,9 @@
message.isflagged = true;
});
});
}
};
function markSelectedMessagesAsUnread() {
this.markSelectedMessagesAsUnread = function() {
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0) {
vm.selectedFolder.$flagMessages(selectedMessages, 'seen', 'remove').then(function(messages) {
@@ -522,9 +507,9 @@
});
});
}
}
};
function markSelectedMessagesAsRead() {
this.markSelectedMessagesAsRead = function() {
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0) {
vm.selectedFolder.$flagMessages(selectedMessages, 'seen', 'add').then(function(messages) {
@@ -535,13 +520,13 @@
});
});
}
}
};
}
angular
.module('material.components.virtualRepeat')
.decorator('mdVirtualRepeatContainerDirective', mdVirtualRepeatContainerDirectiveDecorator);
.module('SOGo.MailerUI')
.controller('MailboxController', MailboxController);
/**
* @ngInject
@@ -560,7 +545,8 @@
}
angular
.module('SOGo.MailerUI')
.controller('MailboxController', MailboxController);
.module('material.components.virtualRepeat')
.decorator('mdVirtualRepeatContainerDirective', mdVirtualRepeatContainerDirectiveDecorator);
})();

View File

@@ -6,70 +6,47 @@
/**
* @ngInject
*/
MailboxesController.$inject = ['$scope', '$state', '$timeout', '$window', '$mdDialog', '$mdToast', '$mdMedia', '$mdSidenav', 'sgConstant', 'sgFocus', 'encodeUriFilter', 'Dialog', 'sgSettings', 'sgHotkeys', 'Account', 'Mailbox', 'VirtualMailbox', 'User', 'Preferences', 'stateAccounts'];
function MailboxesController($scope, $state, $timeout, $window, $mdDialog, $mdToast, $mdMedia, $mdSidenav, sgConstant, focus, encodeUriFilter, Dialog, Settings, sgHotkeys, Account, Mailbox, VirtualMailbox, User, Preferences, stateAccounts) {
MailboxesController.$inject = ['$scope', '$state', '$transitions', '$timeout', '$window', '$mdDialog', '$mdToast', 'sgFocus', 'encodeUriFilter', 'Dialog', 'sgSettings', 'sgHotkeys', 'Account', 'Mailbox', 'VirtualMailbox', 'User', 'Preferences', 'stateAccounts'];
function MailboxesController($scope, $state, $transitions, $timeout, $window, $mdDialog, $mdToast, focus, encodeUriFilter, Dialog, Settings, sgHotkeys, Account, Mailbox, VirtualMailbox, User, Preferences, stateAccounts) {
var vm = this,
account,
mailbox,
hotkeys = [];
vm.service = Mailbox;
vm.accounts = stateAccounts;
vm.toggleAccountState = toggleAccountState;
vm.subscribe = subscribe;
vm.newFolder = newFolder;
vm.delegate = delegate;
vm.editFolder = editFolder;
vm.revertEditing = revertEditing;
vm.selectFolder = selectFolder;
vm.saveFolder = saveFolder;
vm.compactFolder = compactFolder;
vm.emptyTrashFolder = emptyTrashFolder;
vm.confirmDelete = confirmDelete;
vm.markFolderRead = markFolderRead;
vm.share = share;
vm.setFolderAs = setFolderAs;
vm.refreshUnseenCount = refreshUnseenCount;
vm.isDroppableFolder = isDroppableFolder;
vm.dragSelectedMessages = dragSelectedMessages;
this.$onInit = function () {
this.service = Mailbox;
this.accounts = stateAccounts;
// Advanced search options
vm.showingAdvancedSearch = false;
vm.currentSearchParam = '';
vm.addSearchParam = addSearchParam;
vm.newSearchParam = newSearchParam;
vm.showAdvancedSearch = showAdvancedSearch;
vm.hideAdvancedSearch = hideAdvancedSearch;
vm.toggleAdvancedSearch = toggleAdvancedSearch;
vm.search = {
options: {'': '', // no placeholder when no criteria is active
subject: l('Enter Subject'),
from: l('Enter From'),
to: l('Enter To'),
cc: l('Enter Cc'),
body: l('Enter Body')
},
mailbox: 'INBOX',
subfolders: 1,
match: 'AND',
params: []
};
// Advanced search options
this.currentSearchParam = '';
this.search = {
options: {'': '', // no placeholder when no criteria is active
subject: l('Enter Subject'),
from: l('Enter From'),
to: l('Enter To'),
cc: l('Enter Cc'),
body: l('Enter Body')
},
subfolders: 1,
match: 'AND',
params: []
};
Preferences.ready().then(function() {
vm.showSubscribedOnly = Preferences.defaults.SOGoMailShowSubscribedFoldersOnly;
});
vm.refreshUnseenCount();
_registerHotkeys(hotkeys);
$scope.$on('$destroy', function() {
// Deregister hotkeys
_.forEach(hotkeys, function(key) {
sgHotkeys.deregisterHotkey(key);
Preferences.ready().then(function() {
vm.showSubscribedOnly = Preferences.defaults.SOGoMailShowSubscribedFoldersOnly;
});
});
this.refreshUnseenCount();
_registerHotkeys(hotkeys);
$scope.$on('$destroy', function() {
// Deregister hotkeys
_.forEach(hotkeys, function(key) {
sgHotkeys.deregisterHotkey(key);
});
});
};
function _registerHotkeys(keys) {
@@ -88,24 +65,16 @@
});
}
function showAdvancedSearch(path) {
vm.showingAdvancedSearch = true;
vm.search.mailbox = path;
// Close sidenav on small devices
if (!$mdMedia(sgConstant['gt-md']))
$mdSidenav('left').close();
}
function hideAdvancedSearch() {
vm.showingAdvancedSearch = false;
this.hideAdvancedSearch = function() {
vm.service.$virtualPath = false;
vm.service.$virtualMode = false;
account = vm.accounts[0];
mailbox = vm.searchPreviousMailbox;
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(mailbox.path) });
}
};
function toggleAdvancedSearch() {
this.toggleAdvancedSearch = function() {
if (Mailbox.selectedFolder.$isLoading) {
// Stop search
vm.virtualMailbox.stopSearch();
@@ -133,8 +102,8 @@
Mailbox.selectedFolder = vm.virtualMailbox;
Mailbox.$virtualMode = true;
if (angular.isDefined(vm.search.mailbox)) {
root = vm.accounts[0].$getMailboxByPath(vm.search.mailbox);
if (angular.isDefined(Mailbox.$virtualPath)) {
root = vm.accounts[0].$getMailboxByPath(Mailbox.$virtualPath);
mailboxes.push(root);
if (vm.search.subfolders && root.children.length)
_visit(root.children);
@@ -145,17 +114,18 @@
vm.virtualMailbox.setMailboxes(mailboxes);
vm.virtualMailbox.startSearch(vm.search.match, vm.search.params);
$state.go('mail.account.virtualMailbox', { accountId: vm.accounts[0].id });
if ($state.$current.name != 'mail.account.virtualMailbox')
$state.go('mail.account.virtualMailbox', { accountId: vm.accounts[0].id });
}
}
};
function addSearchParam(v) {
this.addSearchParam = function(v) {
vm.currentSearchParam = v;
focus('advancedSearch');
return false;
}
};
function newSearchParam(pattern) {
this.newSearchParam = function(pattern) {
if (pattern.length && vm.currentSearchParam.length) {
var n = 0, searchParam = vm.currentSearchParam;
if (pattern.startsWith("!")) {
@@ -165,9 +135,9 @@
vm.currentSearchParam = '';
return { searchBy: searchParam, searchInput: pattern, negative: n };
}
}
};
function toggleAccountState(account) {
this.toggleAccountState = function (account) {
account.$expanded = !account.$expanded;
account.$flattenMailboxes({ reload: true, saveState: true });
// Fire a window resize to recompute the virtual-repeater.
@@ -176,9 +146,9 @@
$timeout(function() {
angular.element($window).triggerHandler('resize');
}, 150);
}
};
function subscribe(account) {
this.subscribe = function(account) {
$mdDialog.show({
templateUrl: account.id + '/subscribe',
controller: SubscriptionsDialogController,
@@ -212,12 +182,12 @@
});
function close() {
$mdDialog.cancel();
$mdDialog.hide();
}
}
}
};
function newFolder(parentFolder) {
this.newFolder = function(parentFolder) {
Dialog.prompt(l('New Folder...'),
l('Enter the new name of your folder'))
.then(function(name) {
@@ -229,9 +199,9 @@
l(data.error));
});
});
}
};
function delegate(account) {
this.delegate = function(account) {
$mdDialog.show({
templateUrl: account.id + '/delegation', // UI/Templates/MailerUI/UIxMailUserDelegation.wox
controller: MailboxDelegationController,
@@ -285,114 +255,9 @@
}
}
}
} // delegate
}; // delegate
function editFolder(folder) {
vm.editMode = folder.path;
focus('mailboxName_' + folder.path);
}
function revertEditing(folder) {
folder.$reset();
vm.editMode = false;
}
function selectFolder($event, account, folder) {
if (vm.editMode == folder.path)
return;
vm.editMode = false;
vm.showingAdvancedSearch = false;
vm.service.$virtualMode = false;
// Close sidenav on small devices
if (!$mdMedia(sgConstant['gt-md']))
$mdSidenav('left').close();
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(folder.path) });
$event.stopPropagation();
$event.preventDefault();
}
function saveFolder(folder) {
folder.$rename()
.then(function(data) {
vm.editMode = false;
});
}
function compactFolder(folder) {
folder.$compact().then(function() {
$mdToast.show(
$mdToast.simple()
.content(l('Folder compacted'))
.position('top right')
.hideDelay(3000));
});
}
function emptyTrashFolder(folder) {
folder.$emptyTrash().then(function() {
$mdToast.show(
$mdToast.simple()
.content(l('Trash emptied'))
.position('top right')
.hideDelay(3000));
});
}
function confirmDelete(folder) {
Dialog.confirm(l('Warning'),
l('Do you really want to move this folder into the trash ?'),
{ ok: l('Delete') })
.then(function() {
folder.$delete()
.then(function() {
$state.go('mail.account.inbox');
}, function(response) {
Dialog.confirm(l('Warning'),
l('The mailbox could not be moved to the trash folder. Would you like to delete it immediately?'),
{ ok: l('Delete') })
.then(function() {
folder.$delete({ withoutTrash: true })
.then(function() {
$state.go('mail.account.inbox');
}, function(response) {
Dialog.alert(l('An error occured while deleting the mailbox "%{0}".', folder.name),
l(response.error));
});
});
});
});
}
function markFolderRead(folder) {
folder.$markAsRead();
}
function share(folder) {
// Fetch list of ACL users
folder.$acl.$users().then(function() {
// Show ACL editor
$mdDialog.show({
templateUrl: folder.id + '/UIxAclEditor', // UI/Templates/UIxAclEditor.wox
controller: 'AclController', // from the ng module SOGo.Common
controllerAs: 'acl',
clickOutsideToClose: true,
escapeToClose: true,
locals: {
usersWithACL: folder.$acl.users,
User: User,
folder: folder
}
});
});
} // share
function setFolderAs(folder, type) {
folder.$setFolderAs(type).then(function() {
folder.$account.$getMailboxes({reload: true});
});
}
function refreshUnseenCount() {
this.refreshUnseenCount = function() {
var unseenCountFolders = $window.unseenCountFolders;
_.forEach(vm.accounts, function(account) {
@@ -422,13 +287,13 @@
if (refreshViewCheck && refreshViewCheck != 'manually')
$timeout(vm.refreshUnseenCount, refreshViewCheck.timeInterval()*1000);
});
}
};
function isDroppableFolder(srcFolder, dstFolder) {
this.isDroppableFolder = function(srcFolder, dstFolder) {
return (dstFolder.id != srcFolder.id) && !dstFolder.isNoSelect();
}
};
function dragSelectedMessages(srcFolder, dstFolder, mode) {
this.dragSelectedMessages = function(srcFolder, dstFolder, mode) {
var dstId, messages, uids, clearMessageView, promise, success;
dstId = '/' + dstFolder.id;
@@ -456,7 +321,7 @@
.position('top right')
.hideDelay(2000));
});
}
};
}

View File

@@ -206,35 +206,53 @@
if (mailbox) {
mailbox.$topIndex = 0;
mailbox.selectFolder();
return mailbox;
}
else
// Mailbox not found
return $state.go('mail.account.inbox');
return $q.reject("Mailbox doesn't exist");
}
/**
* @ngInject
*/
onEnterInbox.$inject = ['$window', '$state', 'encodeUriFilter', 'stateAccount'];
function onEnterInbox($window, $state, encodeUriFilter, stateAccount) {
if (stateAccount.$mailboxes.length > 0)
$window.location.hash = $state.href('mail.account.mailbox',
{accountId: stateAccount.id,
mailboxId: encodeUriFilter(stateAccount.$mailboxes[0].path)});
else
$state.go('mail');
onEnterInbox.$inject = ['$transition$', 'encodeUriFilter', 'Mailbox'];
function onEnterInbox($transition, encodeUriFilter, Mailbox) {
var stateAccountPromise = $transition.injector().getAsync('stateAccount');
return stateAccountPromise.then(function(stateAccount) {
if (stateAccount.$mailboxes.length > 0) {
return $transition.router.stateService.target('mail.account.mailbox', {
accountId: stateAccount.id,
mailboxId: encodeUriFilter(stateAccount.$mailboxes[0].path)
});
}
else {
Mailbox.selectedFolder = false;
return $transition.router.stateService.target('mail');
}
});
}
/**
* @ngInject
*/
stateMessages.$inject = ['Mailbox', 'stateMailbox'];
function stateMessages(Mailbox, stateMailbox) {
stateMessages.$inject = ['$q', '$state', 'Mailbox', 'stateMailbox'];
function stateMessages($q, $state, Mailbox, stateMailbox) {
var promise;
if (Mailbox.$virtualMode)
return [];
return stateMailbox.$filter();
if (stateMailbox)
promise = stateMailbox.$filter().catch(function() {
// Mailbox not found
return $q.reject('Mailbox not found');
});
else
promise = $q.reject("Mailbox doesn't exist");
return promise;
}
/**
@@ -314,25 +332,21 @@
/**
* @ngInject
*/
// stateContent.$inject = ['stateMessage'];
// function stateContent(stateMessage) {
// return stateMessage.$editableContent();
// }
/**
* @ngInject
*/
runBlock.$inject = ['$rootScope', '$log', '$state', 'Mailbox'];
function runBlock($rootScope, $log, $state, Mailbox) {
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {
$log.error(error);
event.preventDefault();
// Unselect everything
Mailbox.selectedFolder = false;
$state.go('mail');
});
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
$log.error(event, current, previous, rejection);
runBlock.$inject = ['$window', '$transitions', '$log', '$state', 'Mailbox'];
function runBlock($window, $transitions, $log, $state, Mailbox) {
if (!$window.DebugEnabled)
$state.defaultErrorHandler(function() {
// Don't report any state error
});
$transitions.onError({ to: 'mail.**' }, function(transition) {
if (transition.to().name != 'mail' &&
!transition.ignored() &&
transition.error().message.indexOf('superseded') < 0) {
$log.error('transition error to ' + transition.to().name);
// Unselect everything
Mailbox.selectedFolder = false;
$state.go('mail');
}
});
}

View File

@@ -0,0 +1,58 @@
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
(function() {
/**
* sgAccountSection - A directive that is only a controller to manage the selection of the mailboxes.
* @memberof SOGo.MailerUI
*/
function sgAccountSection() {
return {
restrict: 'C',
scope: {},
controller: 'sgAccountController'
};
}
/**
* @ngInject
*/
sgAccountController.$inject = ['$element', '$transitions', '$state', '$mdMedia', '$mdSidenav', 'sgConstant', 'Mailbox', 'encodeUriFilter'];
function sgAccountController($element, $transitions, $state, $mdMedia, $mdSidenav, sgConstant, Mailbox, encodeUriFilter) {
var $ctrl = this, mailboxes = [];
this.$postLink = function () {
this.quotaElement = _.find($element.find('div'), function(div) {
return div.classList.contains('sg-quota');
});
};
// Register a sgMailboxListItem controller
this.addMailboxController = function (mailboxController) {
mailboxes.push(mailboxController);
};
// Called from a sgMailboxListItem controller
this.selectFolder = function (mailboxController) {
if (Mailbox.selectedFolder !== null) {
var selectedMailboxCtrl = _.find(mailboxes, function(ctrl) {
return ctrl.mailbox.id == Mailbox.selectedFolder.id;
});
if (selectedMailboxCtrl)
selectedMailboxCtrl.unselectFolder();
}
// Close sidenav on small devices
if (!$mdMedia(sgConstant['gt-md']))
$mdSidenav('left').close();
};
}
angular
.module('SOGo.MailerUI')
.controller('sgAccountController', sgAccountController)
.directive('sgAccountSection', sgAccountSection);
})();

View File

@@ -0,0 +1,302 @@
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
(function() {
/**
* sgMailboxListItem - A directive that defines the content of a md-list-item for a mailbox.
* @memberof SOGo.MailerUI
*/
function sgMailboxListItem() {
return {
restrict: 'C',
require: {
accountController: '^^sgAccountSection'
},
scope: {},
bindToController: {
mailbox: '=sgMailbox'
},
template: [
' <div class="sg-child-level-0"',
' ng-class="::$ctrl.childLevel()">',
' <md-checkbox class="sg-folder"',
' ng-class="::$ctrl.mailbox.$icon"',
' aria-label="' + l("Expanded") + '"',
' ng-model="$ctrl.mailbox.$expanded"',
' ng-disabled="$ctrl.mailbox.children.length == 0"',
' ng-change="$ctrl.mailbox.$account.$flattenMailboxes({ reload: true, saveState: true })">',
' <md-icon>{{::$ctrl.mailbox.$icon}}</md-icon></md-checkbox>',
' </div>',
' <p class="sg-item-name"',
' ng-click="$ctrl.selectFolder($event)"',
' ng-dblclick="$ctrl.editFolder($event)">',
' <span ng-bind="$ctrl.mailbox.$displayName"></span>',
' <span class="sg-counter-badge ng-hide"',
' ng-show="$ctrl.mailbox.unseenCount"',
' ng-bind="$ctrl.mailbox.unseenCount"></span>',
' </p>',
' <md-input-container class="md-flex ng-hide">',
' <input class="sg-item-name" type="text"',
' aria-label="' + l("Enter the new name of your folder") + '"',
' ng-blur="$ctrl.saveFolder($event)"',
' sg-enter="$ctrl.saveFolder($event)"',
' sg-escape="$ctrl.revertEditing()" />',
' </md-input-container>',
' <md-icon class="md-menu" ng-click="$ctrl.showMenu($event)" aria-label="' + l("Options") + '">more_vert</md-icon>'
].join(''),
controller: 'sgMailboxListItemController',
controllerAs: '$ctrl'
};
}
/**
* @ngInject
*/
sgMailboxListItemController.$inject = ['$scope', '$element', '$compile', '$state', '$mdToast', '$mdPanel', '$mdMedia', '$mdSidenav', 'sgConstant', 'Dialog', 'Mailbox', 'encodeUriFilter'];
function sgMailboxListItemController($scope, $element, $compile, $state, $mdToast, $mdPanel, $mdMedia, $mdSidenav, sgConstant, Dialog, Mailbox, encodeUriFilter) {
var $ctrl = this;
this.$onInit = function() {
this.$element = $element;
this.service = Mailbox;
this.editMode = false;
this.accountController.addMailboxController(this);
};
this.$postLink = function() {
this.selectableElement = $element.find('div')[0];
this.clickableElement = $element.find('p')[0];
this.inputContainer = $element.find('md-input-container')[0];
this.inputElement = $element.find('input')[0];
this.moreOptionsButton = _.last($element.find('md-icon'));
// Check if router's state has selected a mailbox
if (Mailbox.selectedFolder !== null && Mailbox.selectedFolder.id == this.mailbox.id) {
this.selectFolder();
}
};
this.childLevel = function() {
return 'sg-child-level-' + this.mailbox.level;
};
this.selectFolder = function($event) {
if (this.editMode || this.mailbox == Mailbox.selectedFolder)
return;
Mailbox.$virtualPath = false;
Mailbox.$virtualMode = false;
this.accountController.selectFolder(this);
if ($event) {
$state.go('mail.account.mailbox', {
accountId: this.mailbox.$account.id,
mailboxId: encodeUriFilter(this.mailbox.path)
});
$event.stopPropagation();
$event.preventDefault();
}
};
this.unselectFolder = function() {
$element[0].classList.remove('md-bg');
};
this.editFolder = function($event) {
this.editMode = true;
this.inputElement.value = this.mailbox.name;
this.clickableElement.classList.add('ng-hide');
this.inputContainer.classList.remove('ng-hide');
this.inputElement.focus();
this.inputElement.select();
if ($event) {
$event.stopPropagation();
$event.preventDefault();
}
};
this.saveFolder = function($event) {
if (this.inputElement.disabled)
return;
this.mailbox.name = this.inputElement.value;
this.inputElement.disabled = true;
this.mailbox.$rename()
.then(function(data) {
$ctrl.editMode = false;
$ctrl.inputContainer.classList.add('ng-hide');
$ctrl.clickableElement.classList.remove('ng-hide');
})
.finally(function() {
$ctrl.inputElement.disabled = false;
});
};
this.revertEditing = function() {
this.editMode = false;
this.clickableElement.classList.remove('ng-hide');
this.inputContainer.classList.add('ng-hide');
this.inputElement.value = this.mailbox.name;
};
this.showMenu = function($event) {
var panelPosition = $mdPanel.newPanelPosition()
.relativeTo(this.moreOptionsButton)
.addPanelPosition(
$mdPanel.xPosition.ALIGN_START,
$mdPanel.yPosition.ALIGN_TOPS
);
var panelAnimation = $mdPanel.newPanelAnimation()
.openFrom(this.moreOptionsButton)
.duration(100)
.withAnimation($mdPanel.animation.FADE);
var config = {
attachTo: angular.element(document.body),
locals: {
itemCtrl: this,
folder: this.mailbox
},
bindToController: true,
controller: MenuController,
controllerAs: '$menuCtrl',
position: panelPosition,
animation: panelAnimation,
targetEvent: $event,
templateUrl: 'UIxMailFolderMenu',
trapFocus: true,
clickOutsideToClose: true,
escapeToClose: true,
focusOnOpen: true
};
$mdPanel.open(config)
.then(function(panelRef) {
// Automatically close panel when clicking inside of it
panelRef.panelEl.one('click', function() {
panelRef.close();
});
});
MenuController.$inject = ['mdPanelRef', '$state', '$mdDialog', 'User'];
function MenuController(mdPanelRef, $state, $mdDialog, User) {
var $menuCtrl = this;
this.markFolderRead = function() {
this.folder.$markAsRead();
};
this.newFolder = function() {
Dialog.prompt(l('New Folder...'),
l('Enter the new name of your folder'))
.then(function(name) {
$menuCtrl.folder.$newMailbox($menuCtrl.folder.id, name)
.then(function() {
// success
}, function(data, status) {
Dialog.alert(l('An error occured while creating the mailbox "%{0}".', name),
l(data.error));
});
});
};
this.editFolder = function() {
this.itemCtrl.editFolder();
};
this.compactFolder = function() {
this.folder.$compact().then(function() {
$mdToast.show(
$mdToast.simple()
.content(l('Folder compacted'))
.position('top right')
.hideDelay(3000));
});
};
this.emptyTrashFolder = function() {
this.folder.$emptyTrash().then(function() {
$mdToast.show(
$mdToast.simple()
.content(l('Trash emptied'))
.position('top right')
.hideDelay(3000));
});
};
this.confirmDelete = function() {
Dialog.confirm(l('Warning'),
l('Do you really want to move this folder into the trash ?'),
{ ok: l('Delete') })
.then(function() {
$menuCtrl.folder.$delete()
.then(function() {
$state.go('mail.account.inbox');
}, function(response) {
Dialog.confirm(l('Warning'),
l('The mailbox could not be moved to the trash folder. Would you like to delete it immediately?'),
{ ok: l('Delete') })
.then(function() {
$menuCtrl.folder.$delete({ withoutTrash: true })
.then(function() {
$state.go('mail.account.inbox');
}, function(response) {
Dialog.alert(l('An error occured while deleting the mailbox "%{0}".', $menuCtrl.folder.name),
l(response.error));
});
});
});
});
};
this.showAdvancedSearch = function() {
Mailbox.$virtualPath = this.folder.path;
// Close sidenav on small devices
if (!$mdMedia(sgConstant['gt-md']))
$mdSidenav('left').close();
};
this.share = function() {
// Fetch list of ACL users
this.folder.$acl.$users().then(function() {
// Show ACL editor
$mdDialog.show({
templateUrl: $menuCtrl.folder.id + '/UIxAclEditor', // UI/Templates/UIxAclEditor.wox
controller: 'AclController', // from the ng module SOGo.Common
controllerAs: 'acl',
clickOutsideToClose: true,
escapeToClose: true,
locals: {
usersWithACL: $menuCtrl.folder.$acl.users,
User: User,
folder: $menuCtrl.folder
}
});
});
};
this.setFolderAs = function(type) {
this.folder.$setFolderAs(type).then(function() {
$menuCtrl.folder.$account.$getMailboxes({reload: true});
});
};
} // MenuController
};
}
angular
.module('SOGo.MailerUI')
.controller('sgMailboxListItemController', sgMailboxListItemController)
.directive('sgMailboxListItem', sgMailboxListItem);
})();

View File

@@ -0,0 +1,77 @@
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
(function() {
/**
* sgMessageListItem - A directive that watches some attributes of a message. Any component inside the
* list item should depends on this directive and extend the 'onUpdate' method instead of creating new
* independent watchers.
* @memberof SOGo.MailerUI
*/
function sgMessageListItem() {
return {
restrict: 'C',
scope: {},
bindToController: {
message: '=sgMessage'
},
controller: 'sgMessageListItemController'
};
}
/**
* @ngInject
*/
sgMessageListItemController.$inject = ['$scope', '$element', 'Mailbox'];
function sgMessageListItemController($scope, $element, Mailbox) {
var $ctrl = this;
this.$onInit = function () {
// this.service = Message;
this.MailboxService = Mailbox;
$scope.$watch(
function() {
return $ctrl.message? [ _.pick($ctrl.message, ['uid', 'isread', 'isflagged']) ] : null;
},
function(newId, oldId) {
if ($ctrl.message) {
// Message has changed
$ctrl.onUpdate();
}
},
true // compare for object equality
);
};
this.onUpdate = function () {
// Is the message unread?
if (this.message.isread)
$element.removeClass('unread');
else
$element.addClass('unread');
// Is the message selected?
if (Mailbox.selectedFolder.isSelectedMessage(this.message.uid, this.message.$mailbox.path))
$element.addClass('md-default-theme md-accent md-bg md-hue-2');
else
$element.removeClass('md-default-theme md-accent md-bg md-hue-2');
};
this.setVisibility = function (element, visible) {
if (visible)
element.classList.remove('ng-hide');
else
element.classList.add('ng-hide');
};
}
angular
.module('SOGo.MailerUI')
.controller('sgMessageListItemController', sgMessageListItemController)
.directive('sgMessageListItem', sgMessageListItem);
})();

View File

@@ -0,0 +1,181 @@
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
(function() {
/**
* sgMessageListItemMain - The main section of a list item for a message. It relies on the
* 'onUpdate' method of the parent sgMessageListItem controller to update its content.
* @memberof SOGo.MailerUI
* @example:
*/
function sgMessageListItemMain() {
return {
restrict: 'C',
require: '^^sgMessageListItem',
scope: {},
template: [
'<div class="sg-category"',
' ng-repeat="tag in $ctrl.message.flags | limitTo:5"',
' ng-style="{ \'background-color\': $ctrl.service.$tags[tag][1], left: ($index * 3) + \'px\' }"><!-- tags --></div>',
'<div class="sg-tile-content">',
' <div class="sg-md-subhead">',
' <div>',
' <span class="sg-label-outline ng-hide"><!-- mailbox --></span>',
' <md-icon class="ng-hide">error</md-icon>', // the priority icon
' <span><!-- sender or recipient --></span>',
' </div>',
' <div class="sg-tile-date"><!-- date --></div>',
' </div>',
' <div class="sg-md-body">',
' <div class="sg-tile-subject"><!-- subject --></div>',
' <div class="sg-tile-size"><!-- size --></div>',
' </div>',
'</div>',
'<div class="sg-tile-icons">',
' <md-icon class="ng-hide">star</md-icon>',
' <md-icon class="ng-hide">reply</md-icon>',
' <md-icon class="ng-hide">forward</md-icon>',
' <md-icon class="ng-hide">attach_file</md-icon>',
'</div>',
'<div class="sg-progress-linear-bottom">',
' <md-progress-linear class="md-accent"',
' md-mode="indeterminate"',
' ng-disabled="!$ctrl.message.$isLoading()"><!-- message loading progress --></md-progress-linear>',
'</div>'
].join(''),
link: postLink,
controller: 'sgMessageListItemMainController',
controllerAs: '$ctrl'
};
function postLink(scope, element, attrs, parentController) {
scope.parentController = parentController;
}
}
/**
* @ngInject
*/
sgMessageListItemMainController.$inject = ['$scope', '$element', '$parse', '$state', '$mdToast', 'Mailbox', 'Message', 'encodeUriFilter'];
function sgMessageListItemMainController($scope, $element, $parse, $state, $mdToast, Mailbox, Message, encodeUriFilter) {
var $ctrl = this;
this.$postLink = function () {
var contentDivElement, iconsDivElement;
var parentControllerOnUpdate, setVisibility;
this.parentController = $scope.parentController;
parentControllerOnUpdate = this.parentController.onUpdate;
setVisibility = this.parentController.setVisibility;
_.forEach($element.find('div'), function(div) {
if (div.classList.contains('sg-tile-content'))
contentDivElement = angular.element(div);
else if (div.classList.contains('sg-tile-icons'))
iconsDivElement = angular.element(div);
});
this.priorityIconElement = contentDivElement.find('md-icon')[0];
if (Mailbox.$virtualMode) {
// Show mailbox name in front of the subject
this.mailboxNameElement = contentDivElement.find('span')[0];
this.mailboxNameElement.classList.remove('ng-hide');
}
this.senderElement = contentDivElement.find('span')[1];
_.forEach(contentDivElement.find('div'), function(div) {
if (div.classList.contains('sg-tile-subject'))
$ctrl.subjectElement = div;
else if (div.classList.contains('sg-tile-size'))
$ctrl.sizeElement = div;
else if (div.classList.contains('sg-tile-date'))
$ctrl.dateElement = div;
});
_.forEach(iconsDivElement.find('md-icon'), function(div) {
if (div.textContent == 'star')
$ctrl.flagIconElement = div;
else if (div.textContent == 'reply')
$ctrl.answerIconElement = div;
else if (div.textContent == 'forward')
$ctrl.forwardIconElement = div;
else if (div.textContent == 'attach_file')
$ctrl.attachmentIconElement = div;
});
/**
* Update the template when the parent controller has detected a change.
*/
this.parentController.onUpdate = function () {
var i;
$ctrl.message = $ctrl.parentController.message;
console.debug('onUpdate ' + $ctrl.message.uid);
// Flags
for (i = 0; i < $ctrl.message.flags && i < 5; i++) {
var tag = $ctrl.message.flags[i];
var flagElement = angular.element('<div class="sg-category"></div>');
flagElement.css('left', (i*3) + 'px');
flagElement.css('background-color', $ctrl.service.$tags[tag][1]);
$element.prepend(flagElement);
}
// Mailbox name when in virtual mode
if ($ctrl.mailboxNameElement)
$ctrl.mailboxNameElement.innerHTML = $ctrl.message.$mailbox.$displayName;
// Sender or recipient when in
if ($ctrl.MailboxService.selectedFolder.type == 'sent')
$ctrl.senderElement.innerHTML = $ctrl.message.$shortAddress('to').encodeEntities();
else
$ctrl.senderElement.innerHTML = $ctrl.message.$shortAddress('from').encodeEntities();
// Priority icon
if ($ctrl.message.priority && $ctrl.message.priority.level < 3) {
$ctrl.priorityIconElement.classList.remove('ng-hide');
if ($ctrl.message.priority.level < 2)
$ctrl.priorityIconElement.classList.add('md-warn');
else
$ctrl.priorityIconElement.classList.remove('md-warn');
}
else
$ctrl.priorityIconElement.classList.add('ng-hide');
// Subject
$ctrl.subjectElement.innerHTML = $ctrl.message.subject.encodeEntities();
// Message size
$ctrl.sizeElement.innerHTML = $ctrl.message.size;
// Received Date
$ctrl.dateElement.innerHTML = $ctrl.message.relativedate;
setVisibility($ctrl.flagIconElement,
$ctrl.message.isflagged);
setVisibility($ctrl.answerIconElement,
$ctrl.message.isanswered);
setVisibility($ctrl.forwardIconElement,
$ctrl.message.isforwarded);
setVisibility($ctrl.attachmentIconElement,
$ctrl.message.hasattachment);
// Call original method on parent controller
angular.bind($ctrl.parentController, parentControllerOnUpdate)();
};
this.service = Message;
this.MailboxService = Mailbox;
};
}
angular
.module('SOGo.MailerUI')
.controller('sgMessageListItemMainController', sgMessageListItemMainController)
.directive('sgMessageListItemMain', sgMessageListItemMain);
})();

View File

@@ -1,5 +1,9 @@
/// MailerUI.scss -*- Mode: scss; indent-tabs-mode: nil; basic-offset: 2 -*-
.sg-mailbox-list-item:not(.sg-selected) .md-menu {
display: none;
}
.view-list {
// Overwrite style from list.scss to make some place for .sg-tile-icons
md-list-item._md-button-wrap > div.md-button:first-child {
@@ -83,7 +87,7 @@ md-sidenav {
color: rgba(0,0,0,0.54);
font-family: 'Material Icons';
font-size: 24px;
content: "\e2c7";
content: "\e2c7"; // folder
top: -4px;
left: 0px;
width: 1em;
@@ -94,7 +98,7 @@ md-sidenav {
}
&.md-checked {
.md-container:after {
content: "\e2c8";
content: "\e2c8"; // folder open
}
.md-icon {
background-color: initial !important;