mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1069962: show a promo area in the contacts list for Gravatars. Show Gravatar icons upon granting permission. r=Standard8
This commit is contained in:
parent
e914ee6242
commit
58485f44cb
@ -1718,15 +1718,17 @@ pref("loop.debug.dispatcher", false);
|
||||
pref("loop.debug.websocket", false);
|
||||
pref("loop.debug.sdk", false);
|
||||
#ifdef DEBUG
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*; media-src blob:");
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src 'self' data: https://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*; media-src blob:");
|
||||
#else
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net; media-src blob:");
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data: https://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net; media-src blob:");
|
||||
#endif
|
||||
pref("loop.oauth.google.redirect_uri", "urn:ietf:wg:oauth:2.0:oob:auto");
|
||||
pref("loop.oauth.google.scope", "https://www.google.com/m8/feeds");
|
||||
pref("loop.fxa_oauth.tokendata", "");
|
||||
pref("loop.fxa_oauth.profile", "");
|
||||
pref("loop.support_url", "https://support.mozilla.org/kb/group-conversations-firefox-hello-webrtc");
|
||||
pref("loop.contacts.gravatars.show", false);
|
||||
pref("loop.contacts.gravatars.promo", true);
|
||||
|
||||
// serverURL to be assigned by services team
|
||||
pref("services.push.serverURL", "wss://push.services.mozilla.com/");
|
||||
|
@ -117,6 +117,15 @@ const cloneValueInto = function(value, targetWindow) {
|
||||
return clone;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the two-digit hexadecimal code for a byte
|
||||
*
|
||||
* @param {byte} charCode
|
||||
*/
|
||||
const toHexString = function(charCode) {
|
||||
return ("0" + charCode.toString(16)).slice(-2);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject any API containing _only_ function properties into the given window.
|
||||
*
|
||||
@ -740,6 +749,43 @@ function injectLoopAPI(targetWindow) {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Compose a URL pointing to the location of an avatar by email address.
|
||||
* At the moment we use the Gravatar service to match email addresses with
|
||||
* avatars. This might change in the future as avatars might come from another
|
||||
* source.
|
||||
*
|
||||
* @param {String} emailAddress Users' email address
|
||||
* @param {Number} size Size of the avatar image to return in pixels.
|
||||
* Optional. Default value: 40.
|
||||
* @return the URL pointing to an avatar matching the provided email address.
|
||||
*/
|
||||
getUserAvatar: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function(emailAddress, size = 40) {
|
||||
const kEmptyGif = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
||||
if (!emailAddress || !MozLoopService.getLoopPref("contacts.gravatars.show")) {
|
||||
return kEmptyGif;
|
||||
}
|
||||
|
||||
// Do the MD5 dance.
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"]
|
||||
.createInstance(Ci.nsICryptoHash);
|
||||
hasher.init(Ci.nsICryptoHash.MD5);
|
||||
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
stringStream.data = emailAddress.trim().toLowerCase();
|
||||
hasher.updateFromStream(stringStream, -1);
|
||||
let hash = hasher.finish(false);
|
||||
// Convert the binary hash data to a hex string.
|
||||
let md5Email = [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
|
||||
|
||||
// Compose the Gravatar URL.
|
||||
return "https://www.gravatar.com/avatar/" + md5Email + ".jpg?default=blank&s=" + size;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Associates a session-id and a call-id with a window for debugging.
|
||||
*
|
||||
|
@ -229,3 +229,44 @@
|
||||
.contact-form > .button-group {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.contacts-gravatar-promo {
|
||||
position: relative;
|
||||
border: 1px dashed #c1c1c1;
|
||||
border-radius: 2px;
|
||||
background-color: #fbfbfb;
|
||||
padding: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.contacts-gravatar-promo > p {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 8px;
|
||||
margin-right: 4px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
body[dir=rtl] .contacts-gravatar-promo > p {
|
||||
margin-right: 0;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.contacts-gravatar-promo > p > a {
|
||||
color: #0295df;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.contacts-gravatar-promo > p > a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.contacts-gravatar-promo > .button-close {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
body[dir=rtl] .contacts-gravatar-promo > .button-close {
|
||||
right: auto;
|
||||
left: 8px;
|
||||
}
|
||||
|
@ -390,6 +390,23 @@ body {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button-close {
|
||||
background-color: transparent;
|
||||
background-image: url(../shared/img/icons-10x10.svg#close);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 8px 8px;
|
||||
border: none;
|
||||
padding: 0;
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.button-close:hover,
|
||||
.button-close:hover:active {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Dropdown menu */
|
||||
|
||||
.dropdown {
|
||||
|
@ -81,6 +81,59 @@ loop.contacts = (function(_, mozL10n) {
|
||||
contact[field][0].value = value;
|
||||
};
|
||||
|
||||
const GravatarPromo = React.createClass({displayName: "GravatarPromo",
|
||||
propTypes: {
|
||||
handleUse: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
showMe: navigator.mozLoop.getLoopPref("contacts.gravatars.promo") &&
|
||||
!navigator.mozLoop.getLoopPref("contacts.gravatars.show")
|
||||
};
|
||||
},
|
||||
|
||||
handleCloseButtonClick: function() {
|
||||
navigator.mozLoop.setLoopPref("contacts.gravatars.promo", false);
|
||||
this.setState({ showMe: false });
|
||||
},
|
||||
|
||||
handleUseButtonClick: function() {
|
||||
navigator.mozLoop.setLoopPref("contacts.gravatars.promo", false);
|
||||
navigator.mozLoop.setLoopPref("contacts.gravatars.show", true);
|
||||
this.setState({ showMe: false });
|
||||
this.props.handleUse();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.showMe) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let privacyUrl = navigator.mozLoop.getLoopPref("legal.privacy_url");
|
||||
let message = mozL10n.get("gravatars_promo_message", {
|
||||
"learn_more": React.renderToStaticMarkup(
|
||||
React.createElement("a", {href: privacyUrl, target: "_blank"},
|
||||
mozL10n.get("gravatars_promo_message_learnmore")
|
||||
)
|
||||
)
|
||||
});
|
||||
return (
|
||||
React.createElement("div", {className: "contacts-gravatar-promo"},
|
||||
React.createElement(Button, {additionalClass: "button-close", onClick: this.handleCloseButtonClick}),
|
||||
React.createElement("p", {dangerouslySetInnerHTML: {__html: message}}),
|
||||
React.createElement(ButtonGroup, null,
|
||||
React.createElement(Button, {caption: mozL10n.get("gravatars_promo_button_nothanks"),
|
||||
onClick: this.handleCloseButtonClick}),
|
||||
React.createElement(Button, {caption: mozL10n.get("gravatars_promo_button_use"),
|
||||
additionalClass: "button-accept",
|
||||
onClick: this.handleUseButtonClick})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const ContactDropdown = React.createClass({displayName: "ContactDropdown",
|
||||
propTypes: {
|
||||
handleAction: React.PropTypes.func.isRequired,
|
||||
@ -232,7 +285,9 @@ loop.contacts = (function(_, mozL10n) {
|
||||
|
||||
return (
|
||||
React.createElement("li", {className: contactCSSClass, onMouseLeave: this.hideDropdownMenu},
|
||||
React.createElement("div", {className: "avatar"}),
|
||||
React.createElement("div", {className: "avatar"},
|
||||
React.createElement("img", {src: navigator.mozLoop.getUserAvatar(email.value)})
|
||||
),
|
||||
React.createElement("div", {className: "details"},
|
||||
React.createElement("div", {className: "username"}, React.createElement("strong", null, names.firstName), " ", names.lastName,
|
||||
React.createElement("i", {className: cx({"icon icon-google": this.props.contact.category[0] == "google"})}),
|
||||
@ -462,6 +517,12 @@ loop.contacts = (function(_, mozL10n) {
|
||||
}
|
||||
},
|
||||
|
||||
handleUseGravatar: function() {
|
||||
// We got permission to use Gravatar icons now, so we need to redraw the
|
||||
// list entirely to show them.
|
||||
this.refresh();
|
||||
},
|
||||
|
||||
sortContacts: function(contact1, contact2) {
|
||||
let comp = contact1.name[0].localeCompare(contact2.name[0]);
|
||||
if (comp !== 0) {
|
||||
@ -522,7 +583,8 @@ loop.contacts = (function(_, mozL10n) {
|
||||
React.createElement("input", {className: "contact-filter",
|
||||
placeholder: mozL10n.get("contacts_search_placesholder"),
|
||||
valueLink: this.linkState("filter")})
|
||||
: null
|
||||
: null,
|
||||
React.createElement(GravatarPromo, {handleUse: this.handleUseGravatar})
|
||||
),
|
||||
React.createElement("ul", {className: "contact-list"},
|
||||
shownContacts.available ?
|
||||
|
@ -81,6 +81,59 @@ loop.contacts = (function(_, mozL10n) {
|
||||
contact[field][0].value = value;
|
||||
};
|
||||
|
||||
const GravatarPromo = React.createClass({
|
||||
propTypes: {
|
||||
handleUse: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
showMe: navigator.mozLoop.getLoopPref("contacts.gravatars.promo") &&
|
||||
!navigator.mozLoop.getLoopPref("contacts.gravatars.show")
|
||||
};
|
||||
},
|
||||
|
||||
handleCloseButtonClick: function() {
|
||||
navigator.mozLoop.setLoopPref("contacts.gravatars.promo", false);
|
||||
this.setState({ showMe: false });
|
||||
},
|
||||
|
||||
handleUseButtonClick: function() {
|
||||
navigator.mozLoop.setLoopPref("contacts.gravatars.promo", false);
|
||||
navigator.mozLoop.setLoopPref("contacts.gravatars.show", true);
|
||||
this.setState({ showMe: false });
|
||||
this.props.handleUse();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.showMe) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let privacyUrl = navigator.mozLoop.getLoopPref("legal.privacy_url");
|
||||
let message = mozL10n.get("gravatars_promo_message", {
|
||||
"learn_more": React.renderToStaticMarkup(
|
||||
<a href={privacyUrl} target="_blank">
|
||||
{mozL10n.get("gravatars_promo_message_learnmore")}
|
||||
</a>
|
||||
)
|
||||
});
|
||||
return (
|
||||
<div className="contacts-gravatar-promo">
|
||||
<Button additionalClass="button-close" onClick={this.handleCloseButtonClick}/>
|
||||
<p dangerouslySetInnerHTML={{__html: message}}></p>
|
||||
<ButtonGroup>
|
||||
<Button caption={mozL10n.get("gravatars_promo_button_nothanks")}
|
||||
onClick={this.handleCloseButtonClick}/>
|
||||
<Button caption={mozL10n.get("gravatars_promo_button_use")}
|
||||
additionalClass="button-accept"
|
||||
onClick={this.handleUseButtonClick}/>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const ContactDropdown = React.createClass({
|
||||
propTypes: {
|
||||
handleAction: React.PropTypes.func.isRequired,
|
||||
@ -232,7 +285,9 @@ loop.contacts = (function(_, mozL10n) {
|
||||
|
||||
return (
|
||||
<li className={contactCSSClass} onMouseLeave={this.hideDropdownMenu}>
|
||||
<div className="avatar" />
|
||||
<div className="avatar">
|
||||
<img src={navigator.mozLoop.getUserAvatar(email.value)} />
|
||||
</div>
|
||||
<div className="details">
|
||||
<div className="username"><strong>{names.firstName}</strong> {names.lastName}
|
||||
<i className={cx({"icon icon-google": this.props.contact.category[0] == "google"})} />
|
||||
@ -462,6 +517,12 @@ loop.contacts = (function(_, mozL10n) {
|
||||
}
|
||||
},
|
||||
|
||||
handleUseGravatar: function() {
|
||||
// We got permission to use Gravatar icons now, so we need to redraw the
|
||||
// list entirely to show them.
|
||||
this.refresh();
|
||||
},
|
||||
|
||||
sortContacts: function(contact1, contact2) {
|
||||
let comp = contact1.name[0].localeCompare(contact2.name[0]);
|
||||
if (comp !== 0) {
|
||||
@ -523,6 +584,7 @@ loop.contacts = (function(_, mozL10n) {
|
||||
placeholder={mozL10n.get("contacts_search_placesholder")}
|
||||
valueLink={this.linkState("filter")} />
|
||||
: null }
|
||||
<GravatarPromo handleUse={this.handleUseGravatar}/>
|
||||
</div>
|
||||
<ul className="contact-list">
|
||||
{shownContacts.available ?
|
||||
|
Loading…
Reference in New Issue
Block a user