Bug 1074547: improve rendering flow of contacts list. r=Niko

This commit is contained in:
Mike de Boer 2014-10-02 12:59:43 +02:00
parent de69c7b8a1
commit 84fc2dc6c3
3 changed files with 76 additions and 34 deletions

View File

@ -131,6 +131,16 @@ loop.contacts = (function(_, mozL10n) {
document.body.removeEventListener("click", this._onBodyClick);
},
componentShouldUpdate: function(nextProps, nextState) {
let currContact = this.props.contact;
let nextContact = nextProps.contact;
return (
currContact.name[0] !== nextContact.name[0] ||
currContact.blocked !== nextContact.blocked ||
this.getPreferredEmail(currContact).value !== this.getPreferredEmail(nextContact).value
);
},
handleAction: function(actionName) {
if (this.props.handleContactAction) {
this.props.handleContactAction(this.props.contact, actionName);
@ -149,19 +159,20 @@ loop.contacts = (function(_, mozL10n) {
};
},
getPreferredEmail: function() {
// The model currently does not enforce a name to be present, but we're
// going to assume it is awaiting more advanced validation of required fields
// by the model. (See bug 1069918)
let email = this.props.contact.email[0];
this.props.contact.email.some(function(address) {
if (address.pref) {
email = address;
return true;
}
return false;
});
return email;
getPreferredEmail: function(contact = this.props.contact) {
let email;
// A contact may not contain email addresses, but only a phone number instead.
if (contact.email) {
email = contact.email[0];
contact.email.some(function(address) {
if (address.pref) {
email = address;
return true;
}
return false;
});
}
return email || { value: "" };
},
canEdit: function() {
@ -226,11 +237,12 @@ loop.contacts = (function(_, mozL10n) {
// circumvent blocking the main event loop.
let addContactsInChunks = () => {
contacts.splice(0, CONTACTS_CHUNK_SIZE).forEach(contact => {
this.handleContactAddOrUpdate(contact);
this.handleContactAddOrUpdate(contact, false);
});
if (contacts.length) {
setTimeout(addContactsInChunks, 0);
}
this.forceUpdate();
};
addContactsInChunks(contacts);
@ -251,11 +263,13 @@ loop.contacts = (function(_, mozL10n) {
});
},
handleContactAddOrUpdate: function(contact) {
handleContactAddOrUpdate: function(contact, render = true) {
let contacts = this.state.contacts;
let guid = String(contact._guid);
contacts[guid] = contact;
this.setState({});
if (render) {
this.forceUpdate();
}
},
handleContactRemove: function(contact) {
@ -265,7 +279,7 @@ loop.contacts = (function(_, mozL10n) {
return;
}
delete contacts[guid];
this.setState({});
this.forceUpdate();
},
handleContactRemoveAll: function() {

View File

@ -131,6 +131,16 @@ loop.contacts = (function(_, mozL10n) {
document.body.removeEventListener("click", this._onBodyClick);
},
componentShouldUpdate: function(nextProps, nextState) {
let currContact = this.props.contact;
let nextContact = nextProps.contact;
return (
currContact.name[0] !== nextContact.name[0] ||
currContact.blocked !== nextContact.blocked ||
this.getPreferredEmail(currContact).value !== this.getPreferredEmail(nextContact).value
);
},
handleAction: function(actionName) {
if (this.props.handleContactAction) {
this.props.handleContactAction(this.props.contact, actionName);
@ -149,19 +159,20 @@ loop.contacts = (function(_, mozL10n) {
};
},
getPreferredEmail: function() {
// The model currently does not enforce a name to be present, but we're
// going to assume it is awaiting more advanced validation of required fields
// by the model. (See bug 1069918)
let email = this.props.contact.email[0];
this.props.contact.email.some(function(address) {
if (address.pref) {
email = address;
return true;
}
return false;
});
return email;
getPreferredEmail: function(contact = this.props.contact) {
let email;
// A contact may not contain email addresses, but only a phone number instead.
if (contact.email) {
email = contact.email[0];
contact.email.some(function(address) {
if (address.pref) {
email = address;
return true;
}
return false;
});
}
return email || { value: "" };
},
canEdit: function() {
@ -226,11 +237,12 @@ loop.contacts = (function(_, mozL10n) {
// circumvent blocking the main event loop.
let addContactsInChunks = () => {
contacts.splice(0, CONTACTS_CHUNK_SIZE).forEach(contact => {
this.handleContactAddOrUpdate(contact);
this.handleContactAddOrUpdate(contact, false);
});
if (contacts.length) {
setTimeout(addContactsInChunks, 0);
}
this.forceUpdate();
};
addContactsInChunks(contacts);
@ -251,11 +263,13 @@ loop.contacts = (function(_, mozL10n) {
});
},
handleContactAddOrUpdate: function(contact) {
handleContactAddOrUpdate: function(contact, render = true) {
let contacts = this.state.contacts;
let guid = String(contact._guid);
contacts[guid] = contact;
this.setState({});
if (render) {
this.forceUpdate();
}
},
handleContactRemove: function(contact) {
@ -265,7 +279,7 @@ loop.contacts = (function(_, mozL10n) {
return;
}
delete contacts[guid];
this.setState({});
this.forceUpdate();
},
handleContactRemoveAll: function() {

View File

@ -49,6 +49,20 @@
z-index: 1;
}
.contact > .details {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.contact:hover > .details {
/* Hovering the contact shows the icons/ buttons, which takes up horizontal
* space. This causes the fixed-size avatar to resize horizontally, so we assign
* a flex value equivalent to the maximum pixel value to avoid the resizing
* to happen. Consider this a hack. */
flex: 190;
}
.contact > .avatar {
width: 40px;
height: 40px;