Files
shields/frontend/components/customizer/customizer.js
T
Paul MelnikowandGitHub 9e4a8cec09 Consolidate badge URL generation functions (#3032)
This consolidates all the badge URL generation functions into a single place, and updates the rest of the calling code to use it. It renames some things and updates labels to bring the names into alignment with the current API.

Resolve #2027
2019-02-21 21:07:27 -05:00

159 lines
4.1 KiB
JavaScript

import React from 'react'
import PropTypes from 'prop-types'
import clipboardCopy from 'clipboard-copy'
import { staticBadgeUrl } from '../../../core/badge-urls/make-badge-url'
import { generateMarkup } from '../../lib/generate-image-markup'
import { Badge } from '../common'
import PathBuilder from './path-builder'
import QueryStringBuilder from './query-string-builder'
import RequestMarkupButtom from './request-markup-button'
import CopiedContentIndicator from './copied-content-indicator'
export default class Customizer extends React.Component {
static propTypes = {
// This is an item from the `examples` array within the
// `serviceDefinition` schema.
// https://github.com/badges/shields/blob/master/services/service-definitions.js
baseUrl: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
pattern: PropTypes.string.isRequired,
exampleNamedParams: PropTypes.object.isRequired,
exampleQueryParams: PropTypes.object.isRequired,
initialStyle: PropTypes.string,
}
indicatorRef = React.createRef()
state = {
path: '',
link: '',
message: undefined,
}
get baseUrl() {
const { baseUrl } = this.props
if (baseUrl) {
return baseUrl
} else {
// Default to the current hostname for when there is no `BASE_URL` set
// at build time (as in most PaaS deploys).
const { protocol, hostname } = window.location
return `${protocol}//${hostname}`
}
}
generateBuiltBadgeUrl() {
const { baseUrl } = this
const { path, queryString } = this.state
const suffix = queryString ? `?${queryString}` : ''
return `${baseUrl}${path}.svg${suffix}`
}
renderLivePreview() {
// There are some usability issues here. It would be better if the message
// changed from a validation error to a loading message once the
// parameters were filled in, and also switched back to loading when the
// parameters changed.
const { baseUrl } = this.props
const { pathIsComplete } = this.state
let src
if (pathIsComplete) {
src = this.generateBuiltBadgeUrl()
} else {
src = staticBadgeUrl({
baseUrl,
label: 'preview',
message: 'some parameters missing',
})
}
return (
<p>
<Badge display="block" src={src} />
</p>
)
}
copyMarkup = async markupFormat => {
const { title } = this.props
const { link } = this.state
const builtBadgeUrl = this.generateBuiltBadgeUrl()
const markup = generateMarkup({
badgeUrl: builtBadgeUrl,
link,
title,
markupFormat,
})
try {
await clipboardCopy(markup)
} catch (e) {
this.setState({
message: 'Copy failed',
markup,
})
return
}
this.setState({ markup })
this.indicatorRef.current.trigger()
}
renderMarkupAndLivePreview() {
const { indicatorRef } = this
const { markup, message, pathIsComplete } = this.state
return (
<div>
{this.renderLivePreview()}
<CopiedContentIndicator copiedContent="Copied" ref={indicatorRef}>
<RequestMarkupButtom
isDisabled={!pathIsComplete}
onMarkupRequested={this.copyMarkup}
/>
</CopiedContentIndicator>
{message && (
<div>
<p>{message}</p>
<p>Markup: {markup}</p>
</div>
)}
</div>
)
}
handlePathChange = ({ path, isComplete }) => {
this.setState({ path, pathIsComplete: isComplete })
}
handleQueryStringChange = ({ queryString, isComplete }) => {
this.setState({ queryString })
}
render() {
const {
pattern,
exampleNamedParams,
exampleQueryParams,
initialStyle,
} = this.props
return (
<form action="">
<PathBuilder
exampleParams={exampleNamedParams}
onChange={this.handlePathChange}
pattern={pattern}
/>
<QueryStringBuilder
exampleParams={exampleQueryParams}
initialStyle={initialStyle}
onChange={this.handleQueryStringChange}
/>
<div>{this.renderMarkupAndLivePreview()}</div>
</form>
)
}
}