diff options
Diffstat (limited to 'animism-align/frontend/app/views/editor/media/components/media.formGallery.js')
| -rw-r--r-- | animism-align/frontend/app/views/editor/media/components/media.formGallery.js | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/animism-align/frontend/app/views/editor/media/components/media.formGallery.js b/animism-align/frontend/app/views/editor/media/components/media.formGallery.js new file mode 100644 index 0000000..2cf894b --- /dev/null +++ b/animism-align/frontend/app/views/editor/media/components/media.formGallery.js @@ -0,0 +1,338 @@ +import React, { Component } from 'react' +import { Link } from 'react-router-dom' +import { ReactSortable } from "react-sortablejs" + +import actions from 'app/actions' +import { capitalize, simpleArraysEqual } from 'app/utils' +import { preloadImage } from 'app/utils/image.utils' +import { DISPLAY_SIZE, DISPLAY_QUALITY, THUMBNAIL_SIZE, THUMBNAIL_QUALITY } from 'app/constants' + +import { TextInput, LabelDescription, FileInputField, Select, TextArea, Checkbox, SubmitButton, Loader } from 'app/common' +import { renderThumbnail } from 'app/common/upload.helpers' + +import GalleryImageForm from './media.formGalleryImage' + +export default class MediaGalleryForm extends Component { + state = { + loading: false, + edit_image_id: null, + } + + constructor(props) { + super(props) + this.handleSelect = this.handleSelect.bind(this) + this.handleChange = this.handleChange.bind(this) + this.handleSettingsChange = this.handleSettingsChange.bind(this) + this.handleUpload = this.handleUpload.bind(this) + this.uploadSize = this.uploadSize.bind(this) + this.handleSaveItem = this.handleSaveItem.bind(this) + this.handleUploadGalleryThumbnail = this.handleUploadGalleryThumbnail.bind(this) + this.handleDestroyGalleryThumbnail = this.handleDestroyGalleryThumbnail.bind(this) + } + + componentDidMount() { + const { data } = this.props + this.handleSettingsChange('multiple', { + image_order: data.settings.image_order || [], + image_lookup: data.settings.image_lookup || {}, + caption_lookup: data.settings.caption_lookup || {}, + thumbnail_lookup: data.settings.thumbnail_lookup || {}, + }) + } + + handleChange(e) { + const { name, value } = e.target + this.handleSelect(name, value) + } + + handleSelect(name, value) { + this.props.onSelect(name, value) + } + + handleSettingsChange(name, value) { + this.props.onSettingsChange(name, value) + } + + handleUpload(files) { + const { data } = this.props + this.setState({ loading: true }) + this.uploadFullsize(files) + .then(() => { + this.setState({ loading: false }) + }) + } + + handleUploadGalleryThumbnail(file) { + this.setState({ loading: true }) + if (this.props.data.thumbnail) { + this.handleDestroyGalleryThumbnail() + } + this.uploadThumbnail(file, 'thumbnail', THUMBNAIL_SIZE, THUMBNAIL_QUALITY) + .then(thumbnail => { + this.uploadThumbnail(file, 'display', DISPLAY_SIZE, DISPLAY_QUALITY) + .then(display => { + console.log(thumbnail, display) + this.handleSettingsChange('multiple', { + thumbnail, display, + }) + this.setState({ loading: false }) + }) + }) + } + + handleDestroyGalleryThumbnail(e) { + if (e) { + e.preventDefault() + e.stopPropagation() + } + console.log(this.props.data) + actions.upload.destroy({ id: this.props.data.settings.thumbnail.id }) + } + + uploadFullsize(files) { + const { data } = this.props + // first, upload all the fullsize files + let fullsizeUploadPromises = files.map(file => { + return this.uploadSize(file, 'fullsize') + }) + // when these are done + return Promise.all(fullsizeUploadPromises).then(results => { + // get the added IDs in order + const added_image_order = results.map(result => result.id) + // append the new IDs to the image order + const new_image_order = (data.settings.image_order || []).concat(added_image_order) + // add the images to the lookup + const image_lookup = results.reduce((a,b) => { + a[b.id] = b + return a + }, (data.settings.image_lookup || {})) + // add these images to the settings object + this.handleSettingsChange('multiple', { + image_order: new_image_order, + image_lookup: image_lookup, + caption_lookup: data.settings.caption_lookup || {}, + thumbnail_lookup: data.settings.thumbnail_lookup || {}, + }) + return this.uploadResizedFiles(files, added_image_order) + }) + } + + uploadResizedFiles(files, added_image_order) { + return ( + this.uploadThumbnails(files, added_image_order, 'thumbnail', THUMBNAIL_SIZE, THUMBNAIL_QUALITY) + .then(() => { + return this.uploadThumbnails(files, added_image_order, 'display', DISPLAY_SIZE, DISPLAY_QUALITY) + }) + ) + } + + uploadThumbnails(files, added_image_order, tag, maxSide, quality) { + const { data } = this.props + // construct thumbnails and upload these + const thumbnailUploadPromises = files.map(file => { + return this.uploadThumbnail(file, tag, maxSide, quality) + }) + // once the thumbnails are done uploading... + return Promise.all(thumbnailUploadPromises).then(thumbnail_results => { + // decide which lookup we're adding to + const tag_lookup_name = tag + '_lookup' + const tag_lookup = data.settings[tag_lookup_name] || {} + // add them to the thumbnail lookup, keyed off the ID of the fullsize image + const thumbnail_lookup = thumbnail_results.reduce((a, b, i) => { + const id = added_image_order[i] + a[id] = b + return a + }, tag_lookup) + // update the settings object + this.handleSettingsChange('multiple', { + [tag_lookup_name]: thumbnail_lookup, + }) + }) + } + + uploadThumbnail(file, tag, maxSide, quality) { + return new Promise((resolve, reject) => { + const type = (file.name.match('.png') !== -1) ? 'image/png' : 'image/jpg' + const fr = new FileReader() + fr.onload = fileReaderEvent => { + fr.onload = null + const image = new Image() + image.onload = () => { + image.onload = null + const thumbnailCanvas = renderThumbnail(image, { maxSide }) + thumbnailCanvas.toBlob(thumbnail => { + this.uploadSize(thumbnail, tag, file.name) + .then(res => { + resolve(res) + }) + .catch(err => { + reject(err) + }) + }, type, quality) + } + image.src = fileReaderEvent.target.result + } + fr.readAsDataURL(file) + }) + } + + uploadSize(image, tag, fn) { + // console.log('uploading size', tag) + const uploadData = { + image, + tag, + username: 'animism', + } + if (fn) { + uploadData['__image_filename'] = fn + } + // console.log(uploadData) + return actions.upload.upload(uploadData).then(data => { + // console.log(data) + return data.res + }) + } + + handleOrderChanged(new_image_order) { + // console.log(new_image_order) + const image_order = new_image_order.map(el => el.id) + if (!simpleArraysEqual(image_order, this.props.data.settings.image_order)) { + this.handleSettingsChange('image_order', image_order) + } + } + + handleSaveItem(id, item, editNext) { + if (!id) { + this.setState({ edit_image_id: null }) + } + const caption_lookup = this.props.data.settings.caption_lookup || {} + caption_lookup[id] = item + this.handleSettingsChange('caption_lookup', caption_lookup) + if (editNext) { + const image_order = this.props.data.settings.image_order + const index = image_order.indexOf(id) + 1 + if (index < image_order.length) { + this.setState({ edit_image_id: image_order[index] }) + } else { + this.setState({ edit_image_id: null }) + } + } else { + this.setState({ edit_image_id: null }) + } + } + + handleDeleteItem(id) { + let { image_order, image_lookup, thumbnail_lookup, display_lookup, caption_lookup } = this.props.data.settings + const new_image_order = image_order.filter(n => n !== id) + caption_lookup = caption_lookup || {} + const image_lookup_upload_id = ((image_lookup && image_lookup[id]) || {}).id + if (image_lookup_upload_id) { + actions.upload.destroy({ id: image_lookup_upload_id }) + } + const thumbnail_lookup_upload_id = ((thumbnail_lookup && thumbnail_lookup[id]) || {}).id + if (thumbnail_lookup_upload_id) { + actions.upload.destroy({ id: thumbnail_lookup_upload_id }) + } + const display_lookup_upload_id = ((display_lookup && display_lookup[id]) || {}).id + if (display_lookup_upload_id) { + actions.upload.destroy({ id: display_lookup_upload_id }) + } + image_lookup && delete image_lookup[id] + thumbnail_lookup && delete thumbnail_lookup[id] + display_lookup && delete display_lookup[id] + caption_lookup && delete caption_lookup[id] + this.handleSettingsChange('multiple', { + image_order: new_image_order, + image_lookup: { ...image_lookup }, + thumbnail_lookup: { ...thumbnail_lookup }, + display_lookup: { ...display_lookup }, + caption_lookup: { ...caption_lookup }, + }) + } + + render() { + const { data } = this.props + const { image_order, image_lookup, thumbnail_lookup, caption_lookup } = data.settings + const { loading, edit_image_id } = this.state + // console.log(data) + return ( + <div className='galleryForm'> + <FileInputField + multiple + title="Upload images" + mime="*/*" + onChange={this.handleUpload} + /> + {loading && <Loader />} + {image_order && image_order.length && + <ReactSortable + className='galleryList' + list={image_order.map(id => ({ id }))} + setList={new_order => this.handleOrderChanged(new_order)} + > + {image_order.map(image_id => ( + <GalleryListItem + id={image_id} + key={image_id} + image={image_lookup[image_id]} + thumbnail={thumbnail_lookup[image_id]} + onEdit={e => { + e.preventDefault() + e.stopPropagation() + this.setState({ edit_image_id: image_id }) + }} + onDestroy={e => { + e.preventDefault() + e.stopPropagation() + this.handleDeleteItem(image_id) + }} + /> + ))} + </ReactSortable> + } + {edit_image_id && + <GalleryImageForm + id={edit_image_id} + initialData={initialCaptionData(caption_lookup, edit_image_id)} + thumbnail={thumbnail_lookup[edit_image_id]} + onSave={this.handleSaveItem} + /> + } + <FileInputField + title="Upload thumbnail" + mime="*/*" + onChange={this.handleUploadGalleryThumbnail} + /> + {data.settings.thumbnail && + <div className='label'> + <span>Thumbnail</span> + <img src={data.settings.thumbnail.url} /> + <button onClick={this.handleDestroyGalleryThumbnail}>x</button> + </div> + } + </div> + ) + } +} + +const initialCaptionData = (caption_lookup, image_id) => { + caption_lookup = caption_lookup || {} + return caption_lookup[image_id] || {} +} + +const GalleryListItem = ({ id, key, image, thumbnail, onEdit, onDestroy }) => { + // console.log(image, thumbnail) + return ( + <div className='galleryListItem'> + {thumbnail + ? ( + <div> + <div><img src={thumbnail.url} /></div> + <button onClick={onEdit}>Edit</button> + <button onClick={onDestroy}>x</button> + </div> + ) : <Loader /> + } + </div> + ) +} |
