mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-11 15:14:31 +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