mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-09 06:04:33 +08:00
[client-app] convert FocusedContactStore to es6
This commit is contained in:
parent
ebb19b4cd8
commit
ad65b7d77a
2 changed files with 174 additions and 137 deletions
|
@ -1,137 +0,0 @@
|
|||
_ = require 'underscore'
|
||||
Rx = require 'rx-lite'
|
||||
|
||||
Utils = require '../models/utils'
|
||||
Actions = require('../actions').default
|
||||
NylasStore = require 'nylas-store'
|
||||
Thread = require('../models/thread').default
|
||||
Contact = require('../models/contact').default
|
||||
MessageStore = require './message-store'
|
||||
AccountStore = require('./account-store').default
|
||||
DatabaseStore = require('./database-store').default
|
||||
FocusedContentStore = require './focused-content-store'
|
||||
|
||||
# A store that handles the focuses collections of and individual contacts
|
||||
class FocusedContactsStore extends NylasStore
|
||||
constructor: ->
|
||||
@listenTo MessageStore, @_onMessageStoreChanged
|
||||
@listenTo Actions.focusContact, @_onFocusContact
|
||||
@_clearCurrentParticipants()
|
||||
@_triggerLater = _.debounce(@trigger, 250)
|
||||
@_loadCurrentParticipantThreads = _.debounce(@_loadCurrentParticipantThreads, 250)
|
||||
|
||||
sortedContacts: -> @_currentContacts
|
||||
|
||||
focusedContact: -> @_currentFocusedContact
|
||||
|
||||
focusedContactThreads: -> @_currentParticipantThreads ? []
|
||||
|
||||
# We need to wait now for the MessageStore to grab all of the
|
||||
# appropriate messages for the given thread.
|
||||
|
||||
_onMessageStoreChanged: =>
|
||||
threadId = if MessageStore.itemsLoading() then null else MessageStore.threadId()
|
||||
|
||||
# Always clear data immediately when we're showing the wrong thread
|
||||
if @_currentThread and @_currentThread.id isnt threadId
|
||||
@_clearCurrentParticipants()
|
||||
@trigger()
|
||||
|
||||
# Wait to populate until the user has stopped moving through threads. This is
|
||||
# important because the FocusedContactStore powers tons of third-party extensions,
|
||||
# which could do /horrible/ things when we trigger.
|
||||
thread = if MessageStore.itemsLoading() then null else MessageStore.thread()
|
||||
if thread and thread.id isnt @_currentThread?.id
|
||||
@_currentThread = thread
|
||||
@_popuateCurrentParticipants()
|
||||
|
||||
# For now we take the last message
|
||||
_popuateCurrentParticipants: ->
|
||||
@_scoreAllParticipants()
|
||||
sorted = _.sortBy(_.values(@_contactScores), "score").reverse()
|
||||
@_currentContacts = _.map(sorted, (obj) -> obj.contact)
|
||||
@_onFocusContact(@_currentContacts[0])
|
||||
|
||||
_clearCurrentParticipants: ->
|
||||
@_contactScores = {}
|
||||
@_currentContacts = []
|
||||
@_unsubFocusedContact?.dispose()
|
||||
@_unsubFocusedContact = null
|
||||
@_currentFocusedContact = null
|
||||
@_currentThread = null
|
||||
@_currentParticipantThreads = []
|
||||
|
||||
_onFocusContact: (contact) =>
|
||||
@_unsubFocusedContact?.dispose()
|
||||
@_unsubFocusedContact = null
|
||||
@_currentParticipantThreads = []
|
||||
|
||||
if contact
|
||||
query = DatabaseStore.findBy(Contact, {
|
||||
accountId: @_currentThread.accountId,
|
||||
email: contact.email,
|
||||
name: contact.name,
|
||||
})
|
||||
@_unsubFocusedContact = Rx.Observable.fromQuery(query).subscribe (match) =>
|
||||
@_currentFocusedContact = match ? contact
|
||||
@_triggerLater()
|
||||
@_loadCurrentParticipantThreads(contact.email)
|
||||
else
|
||||
@_currentFocusedContact = null
|
||||
@_triggerLater()
|
||||
|
||||
_loadCurrentParticipantThreads: (email) ->
|
||||
email = @_currentFocusedContact?.email
|
||||
return unless email
|
||||
DatabaseStore.findAll(Thread).where(Thread.attributes.participants.contains(email)).limit(100).background().then (threads = []) =>
|
||||
return unless @_currentFocusedContact?.email is email
|
||||
@_currentParticipantThreads = threads
|
||||
@trigger()
|
||||
|
||||
# We score everyone to determine who's the most relevant to display in
|
||||
# the sidebar.
|
||||
_scoreAllParticipants: ->
|
||||
score = (message, msgNum, field, multiplier) =>
|
||||
for contact, j in (message[field] ? [])
|
||||
bonus = message[field].length - j
|
||||
@_assignScore(contact, (msgNum+1) * multiplier + bonus)
|
||||
|
||||
for message, msgNum in MessageStore.items() by -1
|
||||
if message.draft
|
||||
score(message, msgNum, "to", 10000)
|
||||
score(message, msgNum, "cc", 1000)
|
||||
else
|
||||
score(message, msgNum, "from", 100)
|
||||
score(message, msgNum, "to", 10)
|
||||
score(message, msgNum, "cc", 1)
|
||||
|
||||
return @_contactScores
|
||||
|
||||
# Self always gets a score of 0
|
||||
_assignScore: (contact, score=0) ->
|
||||
return unless contact and contact.email
|
||||
return if contact.email.trim().length is 0
|
||||
|
||||
key = Utils.toEquivalentEmailForm(contact.email)
|
||||
|
||||
@_contactScores[key] ?=
|
||||
contact: contact
|
||||
score: score - @_calculatePenalties(contact, score)
|
||||
|
||||
_calculatePenalties: (contact, score) ->
|
||||
penalties = 0
|
||||
email = contact.email.toLowerCase().trim()
|
||||
myEmail = AccountStore.accountForId(@_currentThread?.accountId)?.emailAddress
|
||||
|
||||
if email is myEmail
|
||||
# The whole thing which will penalize to zero
|
||||
penalties += score
|
||||
|
||||
notCommonDomain = not Utils.emailHasCommonDomain(myEmail)
|
||||
sameDomain = Utils.emailsHaveSameDomain(myEmail, email)
|
||||
if notCommonDomain and sameDomain
|
||||
penalties += score * 0.9
|
||||
|
||||
return Math.max(penalties, 0)
|
||||
|
||||
module.exports = new FocusedContactsStore
|
174
packages/client-app/src/flux/stores/focused-contacts-store.es6
Normal file
174
packages/client-app/src/flux/stores/focused-contacts-store.es6
Normal file
|
@ -0,0 +1,174 @@
|
|||
import _ from 'underscore';
|
||||
import Rx from 'rx-lite';
|
||||
import NylasStore from 'nylas-store';
|
||||
|
||||
import Utils from '../models/utils';
|
||||
import Thread from '../models/thread';
|
||||
import Actions from '../actions';
|
||||
import Contact from '../models/contact';
|
||||
import MessageStore from './message-store';
|
||||
import AccountStore from './account-store';
|
||||
import DatabaseStore from './database-store';
|
||||
|
||||
// A store that handles the focuses collections of and individual contacts
|
||||
class FocusedContactsStore extends NylasStore {
|
||||
constructor() {
|
||||
super()
|
||||
this.listenTo(MessageStore, this._onMessageStoreChanged);
|
||||
this.listenTo(Actions.focusContact, this._onFocusContact);
|
||||
this._clearCurrentParticipants();
|
||||
this._triggerLater = _.debounce(this.trigger, 250);
|
||||
this._loadCurrentParticipantThreads = _.debounce(this._loadCurrentParticipantThreads, 250);
|
||||
}
|
||||
|
||||
sortedContacts() { return this._currentContacts; }
|
||||
|
||||
focusedContact() { return this._currentFocusedContact; }
|
||||
|
||||
focusedContactThreads() { return this._currentParticipantThreads || []; }
|
||||
|
||||
// We need to wait now for the MessageStore to grab all of the
|
||||
// appropriate messages for the given thread.
|
||||
|
||||
_onMessageStoreChanged = () => {
|
||||
const threadId = MessageStore.itemsLoading() ? null : MessageStore.threadId();
|
||||
|
||||
// Always clear data immediately when we're showing the wrong thread
|
||||
if (this._currentThread && this._currentThread.id !== threadId) {
|
||||
this._clearCurrentParticipants();
|
||||
this.trigger();
|
||||
}
|
||||
|
||||
// Wait to populate until the user has stopped moving through threads. This is
|
||||
// important because the FocusedContactStore powers tons of third-party extensions,
|
||||
// which could do /horrible/ things when we trigger.
|
||||
const thread = MessageStore.itemsLoading() ? null : MessageStore.thread();
|
||||
if (thread && thread.id !== ((this._currentThread || {}).id)) {
|
||||
this._currentThread = thread;
|
||||
this._populateCurrentParticipants();
|
||||
}
|
||||
}
|
||||
|
||||
// For now we take the last message
|
||||
_populateCurrentParticipants() {
|
||||
this._scoreAllParticipants();
|
||||
const sorted = _.sortBy(_.values(this._contactScores), "score").reverse();
|
||||
this._currentContacts = _.map(sorted, obj => obj.contact);
|
||||
return this._onFocusContact(this._currentContacts[0]);
|
||||
}
|
||||
|
||||
_clearCurrentParticipants() {
|
||||
this._contactScores = {};
|
||||
this._currentContacts = [];
|
||||
if (this._unsubFocusedContact) this._unsubFocusedContact.dispose();
|
||||
this._unsubFocusedContact = null;
|
||||
this._currentFocusedContact = null;
|
||||
this._currentThread = null;
|
||||
this._currentParticipantThreads = [];
|
||||
}
|
||||
|
||||
_onFocusContact = (contact) => {
|
||||
if (this._unsubFocusedContact) this._unsubFocusedContact.dispose();
|
||||
this._unsubFocusedContact = null;
|
||||
this._currentParticipantThreads = [];
|
||||
|
||||
if (contact) {
|
||||
const query = DatabaseStore.findBy(Contact, {
|
||||
accountId: this._currentThread.accountId,
|
||||
email: contact.email,
|
||||
name: contact.name,
|
||||
});
|
||||
this._unsubFocusedContact = Rx.Observable.fromQuery(query).subscribe(match => {
|
||||
this._currentFocusedContact = match || contact;
|
||||
return this._triggerLater();
|
||||
});
|
||||
this._loadCurrentParticipantThreads();
|
||||
} else {
|
||||
this._currentFocusedContact = null;
|
||||
this._triggerLater();
|
||||
}
|
||||
}
|
||||
|
||||
_loadCurrentParticipantThreads() {
|
||||
const currentContact = this._currentFocusedContact || {}
|
||||
const email = currentContact.email;
|
||||
if (!email) {
|
||||
return
|
||||
}
|
||||
DatabaseStore.findAll(Thread)
|
||||
.where(Thread.attributes.participants.contains(email))
|
||||
.limit(100).background()
|
||||
.then((threads = []) => {
|
||||
if (currentContact.email !== email) {
|
||||
return
|
||||
}
|
||||
this._currentParticipantThreads = threads;
|
||||
this.trigger();
|
||||
});
|
||||
}
|
||||
|
||||
// We score everyone to determine who's the most relevant to display in
|
||||
// the sidebar.
|
||||
_scoreAllParticipants() {
|
||||
const score = (message, msgNum, field, multiplier) => {
|
||||
(message[field] || []).forEach((contact, j) => {
|
||||
const bonus = message[field].length - j
|
||||
this._assignScore(contact, (msgNum + 1) * multiplier + bonus)
|
||||
});
|
||||
};
|
||||
|
||||
const iterable = MessageStore.items();
|
||||
for (let msgNum = iterable.length - 1; msgNum >= 0; msgNum--) {
|
||||
const message = iterable[msgNum];
|
||||
if (message.draft) {
|
||||
score(message, msgNum, "to", 10000);
|
||||
score(message, msgNum, "cc", 1000);
|
||||
} else {
|
||||
score(message, msgNum, "from", 100);
|
||||
score(message, msgNum, "to", 10);
|
||||
score(message, msgNum, "cc", 1);
|
||||
}
|
||||
}
|
||||
|
||||
return this._contactScores;
|
||||
}
|
||||
|
||||
// Self always gets a score of 0
|
||||
_assignScore(contact, score = 0) {
|
||||
if (!contact || !contact.email) { return; }
|
||||
if (contact.email.trim().length === 0) { return; }
|
||||
|
||||
const key = Utils.toEquivalentEmailForm(contact.email);
|
||||
|
||||
if (!this._contactScores[key]) {
|
||||
this._contactScores[key] = {
|
||||
contact: contact,
|
||||
score: score - this._calculatePenalties(contact, score),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_calculatePenalties(contact, score) {
|
||||
let penalties = 0;
|
||||
const email = contact.email.toLowerCase().trim();
|
||||
|
||||
const accountId = (this._currentThread || {}).accountId;
|
||||
const account = AccountStore.accountForId(accountId) || {}
|
||||
const myEmail = account.emailAddress
|
||||
|
||||
if (email === myEmail) {
|
||||
// The whole thing which will penalize to zero
|
||||
penalties += score;
|
||||
}
|
||||
|
||||
const notCommonDomain = !Utils.emailHasCommonDomain(myEmail);
|
||||
const sameDomain = Utils.emailsHaveSameDomain(myEmail, email);
|
||||
if (notCommonDomain && sameDomain) {
|
||||
penalties += score * 0.9;
|
||||
}
|
||||
|
||||
return Math.max(penalties, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export default new FocusedContactsStore();
|
Loading…
Add table
Reference in a new issue