$ = jQuery context = window logger = context.JK.logger rest = new context.JK.Rest() @AvatarStore = Reflux.createStore( { listenables: @AvatarActions selection: null updatingAvatar: false targetCropSize: 88 largerCropSize: 200 currentFpfile: null signedCurrentFpfile: null init: -> this.listenTo(context.AppStore, this.onAppInit) onAppInit: (@app) -> onStart: (target, type) -> logger.debug("AvatarStore start", target.id, type) @target = target @type = type @selection = null @updatingAvatar = false @currentFpfile = @determineCurrentFpfile(); @currentCropSelection = @determineCurrentSelection(@target); @signedCurrentFpFile = null @changed() @signFpfile() @app.layout.showDialog('upload-avatar') onSelect: (selection) -> @selection = select @changed() onPick: () -> if @type == 'school' genpolicy = rest.generateSchoolFilePickerPolicy({id: @target.id}) else if @type == 'retailer' genpolicy = rest.generateRetailerFilePickerPolicy({id: @target.id}) genpolicy.done((filepickerPolicy) => @pickerOpen = true @changed() window.filepicker.setKey(gon.fp_apikey); window.filepicker.pickAndStore({ mimetype: 'image/*', maxSize: 10000*1024, policy: filepickerPolicy.policy, signature: filepickerPolicy.signature }, { path: @createStorePath(@target), access: 'public' }, (fpfiles) => ( @pickerOpen = false @afterImageUpload(fpfiles[0]); ), (fperror) => ( @pickerOpen = false @changed() if fperror.code != 101 # 101 just means the user closed the dialog alert("unable to upload file: " + JSON.stringify(fperror)) ) ) ) .fail(@app.ajaxError) afterImageUpload: (fpfile) -> logger.debug("afterImageUploaded", typeof fpfile, fpfile) $.cookie('original_fpfile', JSON.stringify(fpfile)); @currentFpfile = fpfile @signedCurrentFpfile = null @currentCropSelection = null @changed() @signFpfile() signFpfile: () -> if @type == 'school' genpolicy = rest.generateSchoolFilePickerPolicy({id: @target.id}) else if @type == 'retailer' genpolicy = rest.generateRetailerFilePickerPolicy({id: @target.id}) genpolicy.done((policy) => ( @signedCurrentFpfile = @currentFpfile.url + '?signature=' + policy.signature + '&policy=' + policy.policy; @changed() )) getState: () -> { target: @target, type: @type, selection: @selection, updatingAvatar: @updatingAvatar, currentFpfile: @currentFpfile, currentCropSelection: @currentCropSelection, signedCurrentFpfile: @signedCurrentFpfile } changed: () -> state = @getState() logger.debug("change: ", state) @trigger(state) onSelect: (event) -> @selection = event; delete: () -> update: () -> getPolicy: () -> updateAvatarSuccess: (response) -> $.cookie('original_fpfile', null) @target = response # notify any listeners that the avatar changed # userDropdown.loadMe(); # $('.avatar_large img').trigger('avatar_changed', [self.userDetail.photo_url]); # $(document).triggerHandler(EVENTS.USER_UPDATED, response); @app.notify({ title: "Logo Updated", text: "You have updated your avatar successfully." }, null, true); if @type == 'school' window.SchoolActions.refresh() if @type == 'retailer' window.RetailerActions.refresh() @app.layout.closeDialog('upload-avatar') # retrieves a file that has not yet been used as an avatar (uploaded, but not cropped) getWorkingFpfile: () -> return JSON.parse($.cookie('original_fpfile')) createStorePath: (target) -> gon.fp_upload_dir + '/' + @type + '/' + target.id + '/' createOriginalFilename: (target) -> # get the s3 if target.original_fpfile fpfile = JSON.parse(target.original_fpfile) else fpfile = null return 'original_avatar.jpg' determineCurrentFpfile: () -> #precedence is as follows: # * tempOriginal: if set, then the user is working on a new upload # * storedOriginal: if set, then the user has previously uploaded and cropped an avatar # * null: neither are set above tempOriginal = @getWorkingFpfile() if @target.original_fpfile storedOriginal = JSON.parse(@target.original_fpfile) else storedOriginal = null if tempOriginal tempOriginal else storedOriginal determineCurrentSelection: (target) -> # if the cookie is set, don't use the storage selection, just default to null if $.cookie('original_fpfile') == null result = target.crop_selection else result = null if result? JSON.parse(result) else null onDelete: () -> if @updatingAvatar return @updatingAvatar = true @changed() if @type == 'school' rest.deleteSchoolAvatar({id: @target.id}).done((response) => @deleteDone(response)).fail((jqXHR) => @deleteFail(jqXHR)) else if @type == 'retailer' rest.deleteRetailerAvatar({id: @target.id}).done((response) => @deleteDone(response)).fail((jqXHR) => @deleteFail(jqXHR)) deleteDone: (response) -> @currentFpfile = null @signedCurrentFpfile = null @updatingAvatar = false @selection = null @currentCropSelection = null if @type == 'school' window.SchoolActions.refresh() else if @type == 'retailer' window.RetailerActions.refresh() @app.layout.closeDialog('upload-avatar'); @changed() deleteFail: (jqXHR) -> $.cookie('original_fpfile', null) @currentFpfile = null @signedCurrentFpfile = null @selection = null @updatingAvatar = false @currentCropSelection = null @changed() @app.ajaxError(jqXHR) onUpdate: () -> if @updatingAvatar return if @selection? @updatingAvatar = true @changed() currentSelection = @selection logger.debug("Converting..."); fpfile = @determineCurrentFpfile(); if @type == 'school' genpolicy = rest.generateSchoolFilePickerPolicy({ id: @target.id, handle: fpfile.url, convert: true }) else if @type == 'retailer' genpolicy = rest.generateRetailerFilePickerPolicy({ id: @target.id, handle: fpfile.url, convert: true }) genpolicy.done((filepickerPolicy) => window.filepicker.setKey(gon.fp_apikey) window.filepicker.convert(fpfile, { crop: [ Math.round(currentSelection.x), Math.round(currentSelection.y), Math.round(currentSelection.w), Math.round(currentSelection.w)], fit: 'crop', format: 'jpg', quality: 90, policy: filepickerPolicy.policy, signature: filepickerPolicy.signature }, { path: @createStorePath(@target) + 'cropped-' + new Date().getTime() + '.jpg', access: 'public' }, (cropped) => (@scale(cropped)) ) ) else @app.notify( { title: "Upload an Avatar First", text: "To update your avatar, first you must upload an image using the UPLOAD button"}, null, true); scale: (cropped) -> logger.debug("converting cropped"); if @type == 'school' genpolicy = rest.generateSchoolFilePickerPolicy({id: @target.id, handle: cropped.url, convert: true}) else if @type == 'retailer' genpolicy = rest.generateRetailerFilePickerPolicy({id: @target.id, handle: cropped.url, convert: true}) genpolicy.done((filepickerPolicy) => ( window.filepicker.convert(cropped, { height: @targetCropSize, width: @targetCropSize, fit: 'scale', format: 'jpg', quality: 75, policy: filepickerPolicy.policy, signature: filepickerPolicy.signature }, { path: @createStorePath(@target), access: 'public' }, (scaled) => (@scaledLarger(scaled, cropped, filepickerPolicy)), (fperror) => (@handleFpError(fperror))) )) .fail(@app.ajaxError) scaledLarger: (scaled, cropped, filepickerPolicy) -> window.filepicker.convert(cropped, { height: @largerCropSize, width: @largerCropSize, fit: 'scale', format: 'jpg', quality: 75, policy: filepickerPolicy.policy, signature: filepickerPolicy.signature }, { path: @createStorePath(@target) + 'large.jpg', access: 'public' }, (scaledLarger) => (@updateServer(scaledLarger, scaled, cropped)), (fperror) => (@handleFpError(fperror)) ) updateServer: (scaledLarger, scaled, cropped) -> logger.debug("converted and scaled final image %o", scaled); if @type == 'school' update = rest.updateSchoolAvatar({ id: @target.id, original_fpfile: @determineCurrentFpfile(), cropped_fpfile: scaled, cropped_large_fpfile: scaledLarger, crop_selection: @selection }) else if @type == 'retailer' update = rest.updateRetailerAvatar({ id: @target.id, original_fpfile: @determineCurrentFpfile(), cropped_fpfile: scaled, cropped_large_fpfile: scaledLarger, crop_selection: @selection }) update.done((response) => @updateAvatarSuccess(response)) .fail(@app.ajaxError) .always(() => ( @updatingAvatar = false @changed() )) handleFpError: (fperror) -> alert("unable to scale larger selection. error code: " + fperror.code); @updatingAvatar = false; @changed() } )