@behance/helicropter
Advanced tools
Comparing version 14.0.0 to 15.0.0
{ | ||
"name": "@behance/helicropter", | ||
"version": "14.0.0", | ||
"version": "15.0.0", | ||
"description": "My helicropter goes \"whosh whosh whosh\"", | ||
@@ -5,0 +5,0 @@ "main": "src/js/index.js", |
@@ -12,9 +12,65 @@ import extend from '@behance/nbd/util/extend'; | ||
import template from 'hgn-loader!../templates/wrapper'; | ||
import mustache from 'hgn-loader!../templates/wrapper'; | ||
const HelicropterView = View.extend({ | ||
mustache: template, | ||
mustache, | ||
init(...args) { | ||
this._super(...args); | ||
this._uploadArea = new UploadArea({ | ||
uploaderOptions: this._model.get('uploaderOptions'), | ||
backgroundImage: this._model.get('uploadBackgroundImage'), | ||
width: this._model.get('canvasSize').width, | ||
height: this._model.get('canvasSize').height, | ||
titleText: this._model.get('uploadTitle'), | ||
subtitleText: this._model.get('uploadSubtitle'), | ||
hasInitialImage: this._model.get('initialImage'), | ||
}); | ||
this._croppingArea = new CroppingArea({ | ||
canvasWidth: this._model.get('canvasSize').width, | ||
canvasHeight: this._model.get('canvasSize').height, | ||
cropWidth: this._model.get('cropSize').width, | ||
cropHeight: this._model.get('cropSize').height, | ||
displayedWidth: this._model.get('displayedWidth'), | ||
viewportRatio: this._model.get('viewportRatio'), | ||
cropRatio: this._model.get('cropRatio'), | ||
allowTransparency: this._model.get('allowTransparency'), | ||
previewMode: this._model.get('previewMode'), | ||
}); | ||
this._zoomSlider = new ZoomSlider(); | ||
if (this._model.get('showRatioLock')) { | ||
this._ratioLock = new RatioLock({ | ||
labelText: this._model.get('ratioLockText'), | ||
checked: this._model.get('viewportRatio') === 'static', | ||
}); | ||
} | ||
if (this._model.get('showSuggestions')) { | ||
this._suggestionArea = new SuggestionArea({ | ||
suggestions: this._model.get('suggestions'), | ||
maxSuggestions: this._model.get('maxSuggestions'), | ||
}); | ||
} | ||
const config = this._model.get('previewCrop'); | ||
if (config) { | ||
if (!config.element) { | ||
throw new Error('previewCrop.element must be supplied in the configuration'); | ||
} | ||
this._previewCrop = new PreviewCrop({ | ||
cropWidth: this._model.get('cropSize').width, | ||
cropHeight: this._model.get('cropSize').height, | ||
}); | ||
} | ||
this._bindSubsections(); | ||
}, | ||
rendered() { | ||
this._addCroppingArea(); | ||
this._renderCroppingArea(); | ||
@@ -29,9 +85,9 @@ if (this._model.get('previewMode')) { | ||
this._addUploadArea(); | ||
this._addZoomSlider(); | ||
this._addRatioLock(); | ||
this._addSuggestionArea(); | ||
this._addPreviewCrop(); | ||
this._renderUploadArea(); | ||
this._renderSuggestionArea(); | ||
this._bindSubsections(); | ||
this._renderZoomSlider(); | ||
this._renderRatioLock(); | ||
this._renderPreviewCrop(); | ||
this._setInitialState(); | ||
@@ -61,42 +117,16 @@ }, | ||
_addUploadArea() { | ||
this._uploadArea = new UploadArea({ | ||
uploaderOptions: this._model.get('uploaderOptions'), | ||
backgroundImage: this._model.get('uploadBackgroundImage'), | ||
width: this._model.get('canvasSize').width, | ||
height: this._model.get('canvasSize').height, | ||
titleText: this._model.get('uploadTitle'), | ||
subtitleText: this._model.get('uploadSubtitle'), | ||
hasInitialImage: this._model.get('initialImage'), | ||
uploadImmediately: this._model.get('uploadImmediately'), | ||
}); | ||
_renderUploadArea() { | ||
this._uploadArea.render(this.$view.find('.js-upload-container')); | ||
}, | ||
_addCroppingArea() { | ||
this._croppingArea = new CroppingArea({ | ||
canvasWidth: this._model.get('canvasSize').width, | ||
canvasHeight: this._model.get('canvasSize').height, | ||
cropWidth: this._model.get('cropSize').width, | ||
cropHeight: this._model.get('cropSize').height, | ||
displayedWidth: this._model.get('displayedWidth'), | ||
viewportRatio: this._model.get('viewportRatio'), | ||
cropRatio: this._model.get('cropRatio'), | ||
allowTransparency: this._model.get('allowTransparency'), | ||
previewMode: this._model.get('previewMode'), | ||
}); | ||
_renderCroppingArea() { | ||
this._croppingArea.render(this.$view.find('.js-crop-container')); | ||
}, | ||
_addZoomSlider() { | ||
this._zoomSlider = new ZoomSlider(); | ||
_renderZoomSlider() { | ||
this._zoomSlider.render(this.$view.find('.js-crop-controls')); | ||
}, | ||
_addRatioLock() { | ||
_renderRatioLock() { | ||
if (this._model.get('showRatioLock')) { | ||
this._ratioLock = new RatioLock({ | ||
labelText: this._model.get('ratioLockText'), | ||
checked: this._model.get('viewportRatio') === 'static', | ||
}); | ||
this._ratioLock.render(this.$view.find('.js-crop-controls')); | ||
@@ -106,8 +136,4 @@ } | ||
_addSuggestionArea() { | ||
_renderSuggestionArea() { | ||
if (this._model.get('showSuggestions')) { | ||
this._suggestionArea = new SuggestionArea({ | ||
suggestions: this._model.get('suggestions'), | ||
maxSuggestions: this._model.get('maxSuggestions'), | ||
}); | ||
this._suggestionArea.render(this.$view.find('.js-suggestions')); | ||
@@ -117,18 +143,6 @@ } | ||
_addPreviewCrop() { | ||
const config = this._model.get('previewCrop'); | ||
if (!config) { | ||
return; | ||
_renderPreviewCrop() { | ||
if (this._previewCrop) { | ||
this._previewCrop.render(this._model.get('previewCrop').element); | ||
} | ||
if (!config.element) { | ||
throw new Error('previewCrop.element must be supplied in the configuration'); | ||
} | ||
this._previewCrop = new PreviewCrop({ | ||
cropWidth: this._model.get('cropSize').width, | ||
cropHeight: this._model.get('cropSize').height, | ||
}); | ||
this._previewCrop.render(config.element); | ||
}, | ||
@@ -288,3 +302,2 @@ | ||
}, | ||
uploadImmediately: false, | ||
previewMode: false, | ||
@@ -309,2 +322,51 @@ viewportRatio: 'static', | ||
getCroppedImage({ width, height }) { | ||
const canvas = document.createElement('canvas'); | ||
canvas.width = width; | ||
canvas.height = height; | ||
const ctx = canvas.getContext('2d'); | ||
const cropData = this.crop(); | ||
const image = new Image; | ||
return new Promise((resolve, reject) => { | ||
image.onload = () => { | ||
ctx.drawImage( | ||
image, | ||
cropData.dimensions.x, | ||
cropData.dimensions.y, | ||
width, | ||
height, | ||
0, | ||
0, | ||
width, | ||
height, | ||
); | ||
resolve(canvas.toDataURL('image/png')); | ||
}; | ||
image.onerror = () => reject(); | ||
image.src = cropData.src; | ||
}); | ||
}, | ||
uploadThenRender($context) { | ||
if (this._view.$view) { | ||
return; | ||
} | ||
this._view.stopListening(this._view._uploadArea, 'image-uploading'); | ||
this._view.listenOnce(this._view._uploadArea, { | ||
'image-uploading'() { | ||
this.trigger('image:uploading'); | ||
this.render($context); | ||
}, | ||
}); | ||
this.uploadImage(); | ||
}, | ||
changeAspectRatio(ratio) { | ||
@@ -311,0 +373,0 @@ this._view.setCropperAspectRatio(ratio); |
@@ -1,2 +0,1 @@ | ||
import $ from 'jquery'; | ||
import Spinner from 'spin.js'; | ||
@@ -34,15 +33,18 @@ import CloudUploader from '@behance/beff/Component/CloudUploader'; | ||
const Uploader = CloudUploader.extend({ | ||
init($uploadBtn, options) { | ||
const config = {}; | ||
export default View.extend({ | ||
_defaults: { | ||
titleText: 'Upload Image', | ||
subtitleText: '', | ||
}, | ||
if (!options) { | ||
options = $uploadBtn; | ||
$uploadBtn = null; | ||
} | ||
else { | ||
config.button = $uploadBtn; | ||
} | ||
mustache: template, | ||
$.extend(config, { | ||
partials: { | ||
uploadIcon: uploadIcon.template, | ||
}, | ||
init(...args) { | ||
this._super(...args); | ||
const config = Object.assign({ | ||
drift: 0, | ||
@@ -61,20 +63,8 @@ cors: { | ||
}, | ||
}, options); | ||
}, this._model.uploaderOptions); | ||
return this._super(config); | ||
this._uploader = new CloudUploader(config); | ||
this._bind(); | ||
}, | ||
}); | ||
export default View.extend({ | ||
_defaults: { | ||
titleText: 'Upload Image', | ||
subtitleText: '', | ||
}, | ||
mustache: template, | ||
partials: { | ||
uploadIcon: uploadIcon.template, | ||
}, | ||
templateData() { | ||
@@ -92,3 +82,2 @@ this._model.titleText = this._model.titleText == null ? this._defaults.titleText : this._model.titleText; | ||
this._uploader = new Uploader(this._$btn[0], this._model.uploaderOptions); | ||
this._spinner = new Spinner(SPINNER_OPTIONS); | ||
@@ -105,8 +94,3 @@ | ||
this._bindUploader(); | ||
this.on('upload-image', () => this.uploadImage()); | ||
if (this._model.uploadImmediately) { | ||
this.uploadImage(); | ||
} | ||
this._bindUploadButton(); | ||
}, | ||
@@ -140,7 +124,13 @@ | ||
_bindUploader() { | ||
_bindUploadButton() { | ||
this._$btn.on('click', () => this._uploader.choose()); | ||
this.on('upload-image', () => this.uploadImage()); | ||
this.on('image-uploading', () => this._showLoadingState()); | ||
this.on('image-upload-complete upload-error', () => this.showUploadState()); | ||
this.on('image-uploaded', () => this.hide()); | ||
}, | ||
_bind() { | ||
this.listenTo(this._uploader, { | ||
submit() { | ||
this._showLoadingState(); | ||
this.trigger('image-uploading'); | ||
@@ -150,6 +140,5 @@ }, | ||
complete({ file, uploadPath, uploadEndpoint, response }) { | ||
this.showUploadState(); | ||
this.trigger('image-upload-complete'); | ||
if (response && response.success) { | ||
this.hide(); | ||
this._url = `${uploadEndpoint}/${uploadPath}`; | ||
@@ -164,4 +153,2 @@ | ||
error(err) { | ||
this.showUploadState(); | ||
console.error(err); | ||
@@ -172,4 +159,2 @@ this.trigger('upload-error', err); | ||
}, | ||
}, { | ||
Uploader, | ||
}); |
@@ -113,2 +113,48 @@ import $ from 'jquery'; | ||
describe('#uploadThenRender', function() { | ||
it('does not render until the image is submitted', function() { | ||
this.helicropter = new Helicropter(this.defaultConfig); | ||
expect(this.helicropter._view.$view).toBeUndefined(); | ||
this.helicropter.uploadThenRender($('.helicropter-container')); | ||
this.helicropter._view._uploadArea._uploader.trigger('submit'); | ||
expect(this.helicropter._view.$view).toBeDefined(); | ||
}); | ||
it('emits `image:uploading` when the image is submitted', function(done) { | ||
this.helicropter = new Helicropter(this.defaultConfig); | ||
this.helicropter.uploadThenRender($('.helicropter-container')); | ||
this.helicropter.on('image:uploading', done); | ||
this.helicropter._view._uploadArea._uploader.trigger('submit'); | ||
}); | ||
}); | ||
describe('#getCroppedImage', function() { | ||
it('returns cropped image', function(done) { | ||
this.helicropter = this._createWithInitialImage(); | ||
const width = 1; | ||
const height = 1; | ||
const src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='; | ||
spyOn(this.helicropter, 'crop').and.returnValue({ | ||
dimensions: { | ||
x: 1, | ||
y: 1, | ||
}, | ||
src, | ||
}); | ||
this.helicropter.getCroppedImage({ width, height }).then(result => { | ||
expect(result).not.toEqual(src); | ||
expect(result).toContain('data:image/png;base64'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
describe('when given an initial image', function() { | ||
@@ -115,0 +161,0 @@ beforeEach(function() { |
@@ -69,22 +69,2 @@ import $ from 'jquery'; | ||
describe('uploadImmediately option', function() { | ||
beforeEach(function() { | ||
spyOn(UploadArea.Uploader.prototype, 'choose'); | ||
}); | ||
it('allows uploading immediately', function() { | ||
this.uploadArea = this.create({ | ||
uploadImmediately: true, | ||
}); | ||
expect(UploadArea.Uploader.prototype.choose).toHaveBeenCalled(); | ||
}); | ||
it('doesnt upload immediately by default', function() { | ||
this.uploadArea = this.create(); | ||
expect(UploadArea.Uploader.prototype.choose).not.toHaveBeenCalled(); | ||
}); | ||
}); | ||
describe('upload completion', function() { | ||
@@ -91,0 +71,0 @@ it('creates a blob URL for the uploaded image', function(done) { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
8654040
50
4022
1