Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 82 additions & 60 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Gravatar extends React.Component {
protocol: PropTypes.string,
domain: PropTypes.string,
style: PropTypes.object,
fallback: PropTypes.object,
}
static defaultProps = {
size: 50,
Expand All @@ -25,87 +26,108 @@ class Gravatar extends React.Component {
domain: 'www.gravatar.com',
}

constructor(props, context) {
super(props, context);
this.state = {
display: 'image',
}
}

_handleErrors = () => {
if (this.props.fallback) {
this.setState({ display: 'fallback' })
}
}

render() {
const base = `${this.props.protocol}${this.props.domain}/avatar/`
if (this.state.display === 'fallback') {
// Fall back to another default component if the image results in a 404
return this.props.fallback
} else {
const base = `${this.props.protocol}${this.props.domain}/avatar/`

const query = querystring.stringify({
s: this.props.size,
r: this.props.rating,
d: this.props.default,
})
const query = querystring.stringify({
s: this.props.size,
r: this.props.rating,
d: this.props.default,
})

const retinaQuery = querystring.stringify({
s: this.props.size * 2,
r: this.props.rating,
d: this.props.default,
})
const retinaQuery = querystring.stringify({
s: this.props.size * 2,
r: this.props.rating,
d: this.props.default,
})

// Gravatar service currently trims and lowercases all registered emails
const formattedEmail = ('' + this.props.email).trim().toLowerCase();
// Gravatar service currently trims and lowercases all registered emails
const formattedEmail = ('' + this.props.email).trim().toLowerCase();

let hash
if (this.props.md5) {
hash = this.props.md5
} else if (typeof this.props.email === 'string') {
hash = md5(formattedEmail, {encoding: "binary"})
} else {
console.warn(
'Gravatar image can not be fetched. Either the "email" or "md5" prop must be specified.'
)
return (<script />)
}
let hash
if (this.props.md5) {
hash = this.props.md5
} else if (typeof this.props.email === 'string') {
hash = md5(formattedEmail, {encoding: "binary"})
} else {
console.warn(
'Gravatar image can not be fetched. Either the "email" or "md5" prop must be specified.'
)
return (<script />)
}

const src = `${base}${hash}?${query}`
const retinaSrc = `${base}${hash}?${retinaQuery}`
const src = `${base}${hash}?${query}`
const retinaSrc = `${base}${hash}?${retinaQuery}`

let modernBrowser = true // server-side, we render for modern browsers
let modernBrowser = true // server-side, we render for modern browsers

if (typeof window !== 'undefined') {
// this is not NodeJS
modernBrowser = 'srcset' in document.createElement('img')
}
if (typeof window !== 'undefined') {
// this is not NodeJS
modernBrowser = 'srcset' in document.createElement('img')
}

let className = 'react-gravatar'
if (this.props.className) {
className = `${className} ${this.props.className}`
}
let className = 'react-gravatar'
if (this.props.className) {
className = `${className} ${this.props.className}`
}

// Clone this.props and then delete Component specific props so we can
// spread the rest into the img.
let { ...rest } = this.props
delete rest.md5
delete rest.email
delete rest.protocol
delete rest.rating
delete rest.size
delete rest.style
delete rest.className
delete rest.default
if (!modernBrowser && isRetina()) {
// Clone this.props and then delete Component specific props so we can
// spread the rest into the img.
let { ...rest } = this.props
delete rest.md5
delete rest.email
delete rest.protocol
delete rest.rating
delete rest.size
delete rest.style
delete rest.className
delete rest.default
delete rest.fallback
if (!modernBrowser && isRetina()) {
return (
<img
alt={`Gravatar for ${formattedEmail}`}
style={this.props.style}
src={retinaSrc}
height={this.props.size}
width={this.props.size}
{...rest}
className={className}
onError={() => this._handleErrors()}
/>
)
}
return (
<img
alt={this.props.email ? `Gravatar for ${formattedEmail}` : `Gravatar`}
style={this.props.style}
src={retinaSrc}
src={src}
srcSet={`${retinaSrc} 2x`}
height={this.props.size}
width={this.props.size}
{...rest}
className={className}
onError={() => this._handleErrors()}
/>
)
}
return (
<img
alt={`Gravatar for ${formattedEmail}`}
style={this.props.style}
src={src}
srcSet={`${retinaSrc} 2x`}
height={this.props.size}
width={this.props.size}
{...rest}
className={className}
/>
)
}
}

Expand Down