Skip to content

Commit

Permalink
[image-url] Allow using actual query parameters instead of aliases (#792
Browse files Browse the repository at this point in the history
)
  • Loading branch information
rexxars authored May 8, 2018
1 parent c6658b2 commit d36b714
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 85 deletions.
8 changes: 4 additions & 4 deletions packages/@sanity/image-url/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
"main": "index.js",
"scripts": {
"build": "npm run clean && npm run compile",
"coverage": "jest --coverage",
"compile": "babel --source-maps --copy-files -d lib/ src/",
"clean": "rimraf lib",
"postpublish": "npm run clean",
"test": "mocha --recursive --require babel-register test"
"test": "jest"
},
"author": "Sanity.io <[email protected]>",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"devDependencies": {
"mocha": "^5.0.1",
"rimraf": "^2.6.2",
"should": "^11.1.0"
"jest": "^22.4.3",
"rimraf": "^2.6.2"
},
"repository": {
"type": "git",
Expand Down
50 changes: 25 additions & 25 deletions packages/@sanity/image-url/src/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,130 +12,130 @@ class ImageUrlBuilder {
}
}

_withOptions(options) {
withOptions(options) {
return new ImageUrlBuilder(this, options)
}

// The image to be represented. Accepts a Sanity 'image'-document, 'asset'-document or
// _id of asset. To get the benefit of automatic hot-spot/crop integration with the content
// studio, the 'image'-document must be provided.
image(source) {
return this._withOptions({source})
return this.withOptions({source})
}

// Specify the dataset
dataset(dataset) {
return this._withOptions({dataset})
return this.withOptions({dataset})
}

// Specify the projectId
projectId(projectId) {
return this._withOptions({projectId})
return this.withOptions({projectId})
}

// Specify the width of the image in pixels
width(width) {
return this._withOptions({width})
return this.withOptions({width})
}

// Specify the height of the image in pixels
height(height) {
return this._withOptions({height})
return this.withOptions({height})
}

// Specify focal point in fraction of image dimensions. Each component 0.0-1.0
focalPoint(x, y) {
return this._withOptions({focalPoint: {x, y}})
return this.withOptions({focalPoint: {x, y}})
}

maxWidth(maxWidth) {
return this._withOptions({maxWidth})
return this.withOptions({maxWidth})
}

minWidth(minWidth) {
return this._withOptions({minWidth})
return this.withOptions({minWidth})
}

maxHeight(maxHeight) {
return this._withOptions({maxHeight})
return this.withOptions({maxHeight})
}

minHeight(minHeight) {
return this._withOptions({minHeight})
return this.withOptions({minHeight})
}

// Specify width and height in pixels
size(width, height) {
return this._withOptions({width, height})
return this.withOptions({width, height})
}

// Specify blur between 0 and 100
blur(blur) {
return this._withOptions({blur})
return this.withOptions({blur})
}

sharpen(sharpen) {
return this._withOptions({sharpen})
return this.withOptions({sharpen})
}

// Specify the desired rectangle of the image
rect(left, top, width, height) {
return this._withOptions({rect: {left, top, width, height}})
return this.withOptions({rect: {left, top, width, height}})
}

// Specify the image format of the image. 'jpg', 'pjpg', 'png', 'webp'
format(format) {
return this._withOptions({format})
return this.withOptions({format})
}

invert(invert) {
return this._withOptions({invert})
return this.withOptions({invert})
}

// Rotation in degrees 0, 90, 180, 270
orientation(orientation) {
return this._withOptions({orientation})
return this.withOptions({orientation})
}

// Compression quality 0-100
quality(quality) {
return this._withOptions({quality})
return this.withOptions({quality})
}

// Make it a download link. Parameter is default filename.
forceDownload(download) {
return this._withOptions({download})
return this.withOptions({download})
}

// Flip image horizontally
flipHorizontal() {
return this._withOptions({flipHorizontal: true})
return this.withOptions({flipHorizontal: true})
}

// Flip image verically
flipVertical() {
return this._withOptions({flipVertical: true})
return this.withOptions({flipVertical: true})
}

// Ignore crop/hotspot from image record, even when present
ignoreImageParams() {
return this._withOptions({ignoreImageParams: true})
return this.withOptions({ignoreImageParams: true})
}

fit(value) {
if (validFits.indexOf(value) === -1) {
throw new Error(`Invalid fit mode "${value}"`)
}

return this._withOptions({fit: value})
return this.withOptions({fit: value})
}

crop(value) {
if (validCrops.indexOf(value) === -1) {
throw new Error(`Invalid crop mode "${value}"`)
}

return this._withOptions({crop: value})
return this.withOptions({crop: value})
}

// Gets the url based on the submitted parameters
Expand Down
8 changes: 5 additions & 3 deletions packages/@sanity/image-url/src/urlForImage.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export function parseSource(source) {
function parseAssetId(ref) {
const [, id, dimensionString, format] = ref.split('-')

if (!(typeof dimensionString === 'string')) {
if (typeof dimensionString !== 'string') {
throw new Error(
`Malformed asset _ref '${ref}'. Expected an id on the form "image-Tb9Ew8CXIwaY6R1kjMvI0uRR-2000x3000-jpg.`
)
Expand Down Expand Up @@ -168,11 +168,13 @@ function specToImageUrl(spec) {
params.push(`flip=${spec.flipHorizontal ? 'h' : ''}${spec.flipVertical ? 'v' : ''}`)
}

// Map from spec name to url param name
// Map from spec name to url param name, and allow using the actual param name as an alternative
SPEC_NAME_TO_URL_NAME_MAPPINGS.forEach(mapping => {
const [specName, param] = mapping
if (typeof spec[specName] != 'undefined') {
if (typeof spec[specName] !== 'undefined') {
params.push(`${param}=${encodeURIComponent(spec[specName])}`)
} else if (typeof spec[param] !== 'undefined') {
params.push(`${param}=${encodeURIComponent(spec[param])}`)
}
})

Expand Down
2 changes: 1 addition & 1 deletion packages/@sanity/image-url/test/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"env": {
"mocha": true
"jest": true
}
}
48 changes: 40 additions & 8 deletions packages/@sanity/image-url/test/builder.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import should from 'should'
import sanityImage from '../src/builder'
import {imageWithNoCropSpecified, croppedImage} from './fixtures'

Expand All @@ -21,6 +20,28 @@ const cases = [
'https://cdn.sanity.io/images/zp7mbokg/production/Tb9Ew8CXIwaY6R1kjMvI0uRR-2000x3000.jpg?rect=200,300,1600,1280&w=100&h=80'
},

{
name: 'can be told to ignore hotspot',
url: urlFor
.image(croppedImage())
.ignoreImageParams()
.size(100, 80)
.url(),
expect:
'https://cdn.sanity.io/images/zp7mbokg/production/Tb9Ew8CXIwaY6R1kjMvI0uRR-2000x3000.jpg?w=100&h=80'
},

{
name: 'toString() aliases url()',
url: urlFor
.image(croppedImage())
.ignoreImageParams()
.size(100, 80)
.toString(),
expect:
'https://cdn.sanity.io/images/zp7mbokg/production/Tb9Ew8CXIwaY6R1kjMvI0uRR-2000x3000.jpg?w=100&h=80'
},

{
name: 'skips hotspot/crop if crop mode specified',
url: urlFor
Expand Down Expand Up @@ -64,6 +85,16 @@ const cases = [
'https://cdn.sanity.io/images/zp7mbokg/production/vK7bXJPEjVpL_C950gH1N73Zv14r7pYsbUdXl-4288x2848.jpg?rect=720,0,2848,2848&w=80&h=80'
},

{
name: 'can specify options with url params',
url: urlFor
.image(croppedImage())
.withOptions({w: 320, h: 240})
.url(),
expect:
'https://cdn.sanity.io/images/zp7mbokg/production/Tb9Ew8CXIwaY6R1kjMvI0uRR-2000x3000.jpg?rect=200,300,1600,2400&w=320&h=240'
},

{
name: 'all hotspot/crop-compatible params',
url: stripPath(
Expand All @@ -78,6 +109,7 @@ const cases = [
.invert(true)
.orientation(90)
.quality(50)
.sharpen(7)
.forceDownload('a.png')
.flipHorizontal()
.flipVertical()
Expand All @@ -86,7 +118,7 @@ const cases = [
),
// eslint-disable-next-line max-len
expect:
'rect=200,300,1600,2400&flip=hv&fm=png&dl=a.png&blur=50&invert=true&or=90&min-h=150&max-h=300&min-w=100&max-w=200&q=50&fit=crop'
'rect=200,300,1600,2400&flip=hv&fm=png&dl=a.png&blur=50&sharp=7&invert=true&or=90&min-h=150&max-h=300&min-w=100&max-w=200&q=50&fit=crop'
},

{
Expand Down Expand Up @@ -120,16 +152,16 @@ const cases = [

describe('builder', () => {
cases.forEach(testCase => {
it(testCase.name, () => {
should(testCase.url).equal(testCase.expect)
test(testCase.name, () => {
expect(testCase.url).toBe(testCase.expect)
})
})

it('should throw on invalid fit mode', () => {
should.throws(() => urlFor.image(croppedImage()).fit('moo'), /Invalid fit mode "moo"/)
test('should throw on invalid fit mode', () => {
expect(() => urlFor.image(croppedImage()).fit('moo')).toThrowError(/Invalid fit mode "moo"/)
})

it('should throw on invalid crop mode', () => {
should.throws(() => urlFor.image(croppedImage()).crop('moo'), /Invalid crop mode "moo"/)
test('should throw on invalid crop mode', () => {
expect(() => urlFor.image(croppedImage()).crop('moo')).toThrowError(/Invalid crop mode "moo"/)
})
})
2 changes: 1 addition & 1 deletion packages/@sanity/image-url/test/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function croppedImage() {
}
}

export function noHostpotImage() {
export function noHotspotImage() {
return {
_type: 'image',
asset: {
Expand Down
24 changes: 14 additions & 10 deletions packages/@sanity/image-url/test/parseSource.test.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
import should from 'should'
import {parseSource} from '../src/urlForImage'
import {imageWithNoCropSpecified, croppedImage} from './fixtures'

function compareParsedSource(outputSource, exptectedSource) {
should(outputSource).be.an.Object()
should(outputSource.asset).be.an.Object()
should(outputSource.asset._ref).be.eql(exptectedSource.asset._ref)
should(outputSource).have.keys('crop', 'hotspot')
expect(typeof outputSource).toBe('object')
expect(typeof outputSource.asset).toBe('object')
expect(outputSource.asset._ref).toEqual(exptectedSource.asset._ref)
expect(outputSource).toHaveProperty('crop')
expect(outputSource).toHaveProperty('hotspot')
}

describe('parseSource', () => {
it('does correctly parse full image object', () => {
test('does correctly parse full image object', () => {
const parsedSource = parseSource(imageWithNoCropSpecified())
compareParsedSource(parsedSource, imageWithNoCropSpecified())
})

it('does correctly parse asset object', () => {
test('does correctly parse asset object', () => {
const parsedSource = parseSource(imageWithNoCropSpecified().asset._ref)
compareParsedSource(parsedSource, imageWithNoCropSpecified())
})

it('does correctly parse image asset _ref', () => {
test('does correctly parse image asset _ref', () => {
const parsedSource = parseSource(imageWithNoCropSpecified().asset)
compareParsedSource(parsedSource, imageWithNoCropSpecified())
})

it('does not overwrite cropp or hotspot settings', () => {
should(parseSource(croppedImage())).deepEqual(croppedImage())
test('does not overwrite crop or hotspot settings', () => {
expect(parseSource(croppedImage())).toEqual(croppedImage())
})

test('returns null on non-image object', () => {
expect(parseSource({})).toEqual(null)
})
})
Loading

0 comments on commit d36b714

Please sign in to comment.