summaryrefslogtreecommitdiff
path: root/animism-align/frontend/app/views/editor/media/components/media.formGallery.js
diff options
context:
space:
mode:
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.js338
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>
+ )
+}