summaryrefslogtreecommitdiff
path: root/frontend/app/views/page/components/tile.form.js
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2021-03-19 19:10:26 +0100
committerJules Laplace <julescarbon@gmail.com>2021-03-19 19:10:26 +0100
commit17fb6581d305732e2cf0add7f3444e1aa80aec5c (patch)
tree0da40c9f178d3ada44ced2517b6db82b96d8dc19 /frontend/app/views/page/components/tile.form.js
parentccaa55434ff44e0149c5984f2e5968139bbe3baa (diff)
split tile handles into individual files. add video subsection loop
Diffstat (limited to 'frontend/app/views/page/components/tile.form.js')
-rw-r--r--frontend/app/views/page/components/tile.form.js848
1 files changed, 0 insertions, 848 deletions
diff --git a/frontend/app/views/page/components/tile.form.js b/frontend/app/views/page/components/tile.form.js
deleted file mode 100644
index aefecf1..0000000
--- a/frontend/app/views/page/components/tile.form.js
+++ /dev/null
@@ -1,848 +0,0 @@
-import React, { Component } from 'react'
-import { connect } from 'react-redux'
-import { bindActionCreators } from 'redux'
-import { Link } from 'react-router-dom'
-
-import actions from 'app/actions'
-import { session } from 'app/session'
-
-import {
- TextInput, NumberInput, ColorInput, Slider,
- Select, LabelDescription, TextArea, Checkbox,
- SubmitButton, Loader } from 'app/common'
-import AudioSelect from 'app/views/audio/components/audio.select'
-import { preloadImage, preloadVideo } from 'app/utils'
-
-import * as tileActions from '../../tile/tile.actions'
-
-const SELECT_TYPES = [
- "image", "text", "video", "link", "script",
-].map(s => ({ name: s, label: s }))
-
-const ALIGNMENTS = [
- "top_left", "top_center", "top_right",
- "center_left", "center_center", "center_right",
- "bottom_left", "bottom_center", "bottom_right",
-].map(align => ({
- name: align,
- label: align === 'center_center'
- ? 'center'
- : align.replace('_', ' ')
- }))
-
-const REQUIRED_KEYS = {
- image: ['url'],
- video: ['url'],
- text: ['content'],
- link: [],
- script: [],
-}
-
-const IMAGE_TILE_STYLES = [
- 'tile', 'cover', 'contain', 'contain no-repeat'
-].map(style => ({ name: style, label: style }))
-
-const VIDEO_STYLES = [
- 'normal', 'cover', 'contain',
-].map(style => ({ name: style, label: style }))
-
-const TEXT_FONT_FAMILIES = [
- 'sans-serif', 'serif', 'fantasy', 'monospace', 'cursive',
-].map(style => ({ name: style, label: style }))
-
-const TEXT_FONT_STYLES = [
- 'normal', 'bold', 'italic', 'bold-italic',
-].map(style => ({ name: style, label: style }))
-
-const CURSORS = [
- { name: 'none', label: 'None', },
- { name: 'hand_up', label: 'Up', },
- { name: 'hand_down', label: 'Down', },
- { name: 'hand_left', label: 'Left', },
- { name: 'hand_right', label: 'Right', },
- { name: 'unclickable', label: 'Unclickable', },
-]
-
-const NO_LINK = 0
-const EXTERNAL_LINK = -1
-const PAGE_LIST_TOP_OPTIONS = [
- { name: NO_LINK, label: 'No link' },
- { name: EXTERNAL_LINK, label: 'External link' },
- { name: -2, label: '──────────', disabled: true },
-]
-
-// target_page_id = Column(Integer, ForeignKey('page.id'), nullable=True)
-// https://s3.amazonaws.com/i.asdf.us/im/1c/gradient_gold1-SpringGreen1_1321159749.jpg
-
-const newImage = (data) => ({
- settings: {
- ...newPosition(),
- is_tiled: false,
- tile_style: 'tile',
- url: "",
- external_link_url: "",
- cursor: 'hand_up',
- },
- type: 'image',
- target_page_id: null,
- ...data,
-})
-
-const newVideo = (data) => ({
- settings: {
- ...newPosition(),
- video_style: 'cover',
- url: "",
- external_link_url: "",
- cursor: 'none',
- muted: false,
- loop: false,
- autoadvance: false,
- },
- type: 'video',
- target_page_id: null,
- ...data,
-})
-
-const newText = (data) => ({
- settings: {
- ...newPosition(),
- content: "",
- font_family: 'sans-serif',
- font_size: 16,
- font_style: 'normal',
- font_color: '#dddddd',
- background_color: 'transparent',
- width: 0,
- height: 0,
- units: 'px',
- external_link_url: "",
- cursor: 'hand_up',
- },
- type: 'text',
- target_page_id: null,
- ...data,
-})
-
-const newLink = (data) => ({
- settings: {
- ...newPosition({ width: 100, height: 100, }),
- external_link_url: "",
- cursor: 'hand_up',
- units: 'px',
- },
- type: 'link',
- target_page_id: null,
- ...data,
-})
-
-const newScript = (data) => ({
- settings: {
- ...newPosition({ width: 100, height: 100, }),
- },
- type: 'script',
- ...data,
-})
-
-const newPosition = (data) => ({
- x: 0, y: 0,
- width: 0, height: 0,
- rotation: 0, scale: 1,
- opacity: 1,
- units: false,
- align: "center_center",
- has_audio: false,
- audio_on_click_id: 0,
- audio_on_hover_id: 0,
- navigate_when_audio_finishes: false,
- ...data,
-})
-
-const TYPE_CONSTRUCTORS = {
- image: newImage,
- video: newVideo,
- text: newText,
- link: newLink,
- script: newScript,
-}
-
-class TileForm extends Component {
- state = {
- title: "",
- submitTitle: "",
- errorFields: new Set([]),
- modified: false,
- pageList: [],
- }
-
- constructor(props){
- super(props)
- this.handleChange = this.handleChange.bind(this)
- this.handleSelect = this.handleSelect.bind(this)
- this.handleSettingsChange = this.handleSettingsChange.bind(this)
- this.handleSettingsSelect = this.handleSettingsSelect.bind(this)
- this.handleAlignment = this.handleAlignment.bind(this)
- this.handleImageChange = this.handleImageChange.bind(this)
- this.handleVideoChange = this.handleVideoChange.bind(this)
- this.handleSubmit = this.handleSubmit.bind(this)
- this.handleDelete = this.handleDelete.bind(this)
- }
-
- componentDidMount() {
- const { graph, page, isNew, initialData, sortOrder } = this.props
- const title = isNew ? 'new tile' : 'editing tile'
- const submitTitle = isNew ? "Create Tile" : "Save Changes"
- this.setState({
- title,
- submitTitle,
- errorFields: new Set([]),
- })
- const { pages } = graph.show.res
- const linkPages = initialData ? pages.filter(page => page.id !== initialData.id) : pages
- let pageList = [
- ...PAGE_LIST_TOP_OPTIONS,
- ...linkPages.map(page => ({ name: page.id, label: page.path }))
- ]
- this.setState({ pageList })
- if (isNew) {
- const newTile = newImage({
- id: "new",
- graph_id: graph.show.res.id,
- page_id: page.show.res.id,
- sort_order: sortOrder,
- })
- this.props.tileActions.updateTemporaryTile(newTile)
- } else {
- this.props.tileActions.updateTemporaryTile({ ...initialData })
- }
- }
-
- componentDidUpdate(prevProps) {
- if (!this.props.isNew && this.props.initialData !== prevProps.initialData) {
- this.handleSubmit()
- this.props.tileActions.updateTemporaryTile({ ...this.props.initialData })
- this.setState({
- errorFields: new Set([]),
- })
- }
- }
-
- componentWillUnmount() {
- // if the item has changed, save before we close the form!
- if (!this.props.isNew && this.state.modified) {
- this.handleSubmit()
- }
- }
-
- handleChange(e) {
- const { name, value } = e.target
- this.clearErrorField(name)
- this.props.tileActions.updateTemporaryTile({
- ...this.props.temporaryTile,
- [name]: value,
- })
- }
-
- handleTypeChange(type) {
- const { graph, page, temporaryTile } = this.props
- let newTile = TYPE_CONSTRUCTORS[type]({
- id: temporaryTile.id,
- graph_id: temporaryTile.graph_id,
- page_id: temporaryTile.page_id,
- })
- newTile.settings.align = temporaryTile.settings.align
- this.clearErrorField('type')
- this.props.tileActions.updateTemporaryTile(newTile)
- }
-
- handleSettingsChange(e) {
- const { name, value } = e.target
- this.clearErrorField(name)
- this.props.tileActions.updateTemporaryTile({
- ...this.props.temporaryTile,
- settings: {
- ...this.props.temporaryTile.settings,
- [name]: value,
- }
- })
- }
-
- handleSelect(name, value) {
- this.clearErrorField(name)
- if (name === 'type') {
- return this.handleTypeChange(value)
- }
- if (name === 'target_page_id') {
- value = parseInt(value)
- }
- this.props.tileActions.updateTemporaryTile({
- ...this.props.temporaryTile,
- [name]: value,
- })
- }
-
- handleSettingsSelect(name, value) {
- this.clearErrorField(name)
- this.props.tileActions.updateTemporaryTile({
- ...this.props.temporaryTile,
- settings: {
- ...this.props.temporaryTile.settings,
- [name]: value,
- }
- })
- }
-
- handleAlignment(name, value) {
- this.clearErrorField(name)
- this.props.tileActions.updateTemporaryTile({
- ...this.props.temporaryTile,
- settings: {
- ...this.props.temporaryTile.settings,
- [name]: value,
- x: 0, y: 0,
- }
- })
- }
-
- handleImageChange(e) {
- const { name, value } = e.target
- this.handleSettingsSelect(name, value)
- preloadImage(value).then(img => {
- // console.log(img)
- this.props.tileActions.updateTemporaryTile({
- ...this.props.temporaryTile,
- settings: {
- ...this.props.temporaryTile.settings,
- [name]: value,
- width: img.naturalWidth,
- height: img.naturalHeight,
- x: 0, y: 0,
- }
- })
- })
- }
-
- handleVideoChange(e) {
- const { name, value } = e.target
- this.handleSettingsSelect(name, value)
- preloadVideo(value).then(video => {
- // console.log(img)
- this.props.tileActions.updateTemporaryTile({
- ...this.props.temporaryTile,
- settings: {
- ...this.props.temporaryTile.settings,
- [name]: value,
- width: video.videoWidth,
- height: video.videoHeight,
- x: 0, y: 0,
- }
- })
- })
- }
-
- clearErrorField(name) {
- const { errorFields } = this.state
- if (errorFields.has(name)) {
- errorFields.delete(name)
- this.setState({
- errorFields,
- modified: true,
- })
- } else if (!this.state.modified) {
- this.setState({
- errorFields,
- modified: true,
- })
- }
- }
-
- handleSubmit(e) {
- if (e) e.preventDefault()
- const { isNew, temporaryTile, onSubmit, onClose } = this.props
- const requiredSettings = REQUIRED_KEYS[temporaryTile.type]
- const validKeys = "id graph_id page_id target_page_id type settings".split(" ")
- const validData = validKeys.reduce((a,b) => { a[b] = temporaryTile[b]; return a }, {})
- const errorFields = requiredSettings.filter(key => !validData.settings[key])
- if (errorFields.length) {
- console.log('error', errorFields, validData)
- if (e) {
- this.setState({ errorFields: new Set(errorFields) })
- }
- } else {
- if (isNew) {
- // side effect: set username if we're creating a new tile
- // session.set('username', data.username)
- delete validData.id
- } else {
- validData.id = temporaryTile.id
- }
- this.setState({ modified: false })
- console.log('submit', validData)
- onSubmit(validData)
- // if submitting after switching elements, don't close the form
- if (e && onClose) {
- onClose()
- }
- }
- }
-
- handleDelete() {
- const { temporaryTile, isNew, onClose } = this.props
- if (confirm('Really delete this tile?')) {
- actions.tile.destroy(temporaryTile)
- .then(() => {
- onClose()
- })
- }
- }
-
- render() {
- const { temporaryTile, isNew } = this.props
- const { title, submitTitle, errorFields } = this.state
- if (!temporaryTile || !temporaryTile.settings) return <div className='box' />
- return (
- <div className='box'>
- <h1>{title}</h1>
- <form onSubmit={this.handleSubmit}>
- <div className="row selects">
- <Select
- name='type'
- selected={temporaryTile.type}
- options={SELECT_TYPES}
- title=''
- onChange={this.handleSelect}
- />
- <Select
- name='align'
- selected={temporaryTile.settings.align}
- options={ALIGNMENTS}
- title=''
- onChange={this.handleAlignment}
- />
- </div>
-
- {this.renderPositionInfo()}
-
- {temporaryTile.type === 'image'
- ? this.renderImageForm()
- : temporaryTile.type === 'video'
- ? this.renderVideoForm()
- : temporaryTile.type === 'text'
- ? this.renderTextForm()
- : temporaryTile.type === 'link'
- ? this.renderLinkForm()
- : temporaryTile.type === 'script'
- ? this.renderScriptForm()
- : ""}
-
- {this.renderHyperlinkForm()}
- {this.renderMiscForm()}
- {this.renderAudioForm()}
-
- <div className='row buttons'>
- <SubmitButton
- title={submitTitle}
- onClick={this.handleSubmit}
- />
- {!isNew &&
- <SubmitButton
- title={'Delete'}
- className='destroy'
- onClick={this.handleDelete}
- />
- }
- </div>
- {!!errorFields.size &&
- <label>
- <span></span>
- <span>Please add the required fields =)</span>
- </label>
- }
- </form>
- </div>
- )
- }
-
- renderPositionInfo() {
- const { temporaryTile } = this.props
- const { x, y, width, height, rotation, scale } = temporaryTile.settings
- return (
- <div className='position'>
- {parseInt(x)}{', '}
- {parseInt(y)}{' '}
- {parseInt(width)}{'x'}{parseInt(height)}{' '}
- {rotation === 0 || <span>{parseInt(rotation)}{'\u00B0 '}</span>}
- {scale === 1 || <span>{'x'}{scale.toFixed(2)}</span>}
- </div>
- )
- }
-
- renderImageForm() {
- // const { isNew } = this.props
- const { temporaryTile } = this.props
- const { errorFields } = this.state
- // console.log(temporaryTile.settings)
- return (
- <div>
- <div className='row imageUrl'>
- {temporaryTile.settings.url && <div className='thumb'><img src={temporaryTile.settings.url} /></div>}
- <TextInput
- title=""
- placeholder='http://'
- name="url"
- required
- data={temporaryTile.settings}
- error={errorFields.has('url')}
- onChange={this.handleImageChange}
- autoComplete="off"
- />
- </div>
- <div className='row pair'>
- <Checkbox
- label="Tiled"
- name="is_tiled"
- checked={temporaryTile.settings.is_tiled}
- onChange={this.handleSettingsSelect}
- autoComplete="off"
- />
- {temporaryTile.settings.is_tiled &&
- <Select
- name='tile_style'
- selected={temporaryTile.settings.tile_style || 'tile'}
- options={IMAGE_TILE_STYLES}
- title=''
- onChange={this.handleSettingsSelect}
- />
- }
- </div>
- </div>
- )
- }
-
- renderVideoForm() {
- // const { isNew } = this.props
- const { temporaryTile } = this.props
- const { errorFields } = this.state
- // console.log(temporaryTile.settings)
- return (
- <div>
- <div className='row imageUrl'>
- <TextInput
- title=""
- placeholder='http://'
- name="url"
- required
- data={temporaryTile.settings}
- error={errorFields.has('url')}
- onChange={this.handleVideoChange}
- autoComplete="off"
- />
- </div>
- <div className='row pair'>
- <Select
- name='video_style'
- selected={temporaryTile.settings.video_style || 'none'}
- options={VIDEO_STYLES}
- title=''
- onChange={this.handleSettingsSelect}
- />
- <Checkbox
- label="Loop"
- name="loop"
- checked={temporaryTile.settings.loop}
- onChange={this.handleSettingsSelect}
- autoComplete="off"
- />
- </div>
- <div className='row pair'>
- <Checkbox
- label="Muted"
- name="muted"
- checked={temporaryTile.settings.muted}
- onChange={this.handleSettingsSelect}
- autoComplete="off"
- />
- <Checkbox
- label="Autoadvance"
- name="autoadvance"
- checked={temporaryTile.settings.autoadvance}
- onChange={this.handleSettingsSelect}
- autoComplete="off"
- />
- </div>
- </div>
- )
- }
-
- renderTextForm() {
- const { temporaryTile } = this.props
- const { errorFields } = this.state
- return (
- <div>
- <TextArea
- title=""
- name="content"
- required
- data={temporaryTile.settings}
- error={errorFields.has('content')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- <div className='row font'>
- <Select
- title="Font"
- name='font_family'
- selected={temporaryTile.settings.font_family || 'sans-serif'}
- options={TEXT_FONT_FAMILIES}
- title=''
- onChange={this.handleSettingsSelect}
- />
- <NumberInput
- title=''
- name='font_size'
- data={temporaryTile.settings}
- min={1}
- max={1200}
- error={errorFields.has('font_size')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- <Select
- name='font_style'
- selected={temporaryTile.settings.font_style || 'normal'}
- options={TEXT_FONT_STYLES}
- title=''
- onChange={this.handleSettingsSelect}
- />
- </div>
- <ColorInput
- title='Text'
- name='font_color'
- data={temporaryTile.settings}
- error={errorFields.has('font_color')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- <ColorInput
- title='BG'
- name='background_color'
- data={temporaryTile.settings}
- error={errorFields.has('background_color')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- <div className='row pair'>
- <NumberInput
- title="Width"
- name="width"
- data={temporaryTile.settings}
- min={0}
- max={1200}
- error={errorFields.has('width')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- <NumberInput
- title="Height"
- name="height"
- data={temporaryTile.settings}
- min={0}
- max={1200}
- error={errorFields.has('height')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- </div>
- </div>
- )
- }
-
- renderLinkForm() {
- const { temporaryTile } = this.props
- const { errorFields } = this.state
- return (
- <div>
- <div className='row pair'>
- <NumberInput
- title="Width"
- name="width"
- data={temporaryTile.settings}
- min={0}
- max={1200}
- error={errorFields.has('width')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- <NumberInput
- title="Height"
- name="height"
- data={temporaryTile.settings}
- min={0}
- max={1200}
- error={errorFields.has('height')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- </div>
- <div className='row pair'>
- <TextInput
- title="Units"
- name="units"
- data={temporaryTile.settings}
- error={errorFields.has('units')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- </div>
- </div>
- )
- }
-
- renderScriptForm() {
- const { temporaryTile } = this.props
- const { errorFields } = this.state
- return (
- <div>
- <TextArea
- title=""
- name="content"
- required
- data={temporaryTile.settings}
- error={errorFields.has('content')}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- <div>
- Scripts will be run on the live site when this page loads.
- </div>
- </div>
- )
- }
-
- renderHyperlinkForm() {
- const { temporaryTile } = this.props
- const { pageList } = this.state
- const isExternalLink = temporaryTile.target_page_id === EXTERNAL_LINK
- return (
- <div>
- <div className={'row selects'}>
- <Select
- title=''
- name='target_page_id'
- selected={temporaryTile.target_page_id || NO_LINK}
- options={pageList}
- onChange={this.handleSelect}
- />
- <Select
- title=''
- name='cursor'
- selected={temporaryTile.settings.cursor}
- options={CURSORS}
- defaultOption="Cursor"
- onChange={this.handleSettingsSelect}
- />
- </div>
- <div>
- {isExternalLink &&
- <TextInput
- title=""
- placeholder='http://'
- name="external_link_url"
- data={temporaryTile.settings}
- onChange={this.handleSettingsChange}
- autoComplete="off"
- />
- }
- </div>
- </div>
- )
- }
-
- renderAudioForm() {
- const { temporaryTile } = this.props
- return (
- <div>
- <Checkbox
- label="Play audio"
- name="has_audio"
- checked={temporaryTile.settings.has_audio}
- onChange={this.handleSettingsSelect}
- />
- {temporaryTile.settings.has_audio && (
- <div >
- <AudioSelect
- title="On click"
- name="audio_on_click_id"
- selected={temporaryTile.settings.audio_on_click_id}
- onChange={this.handleSettingsSelect}
- />
-
- <Checkbox
- label="Navigate when audio finishes"
- name="navigate_when_audio_finishes"
- checked={temporaryTile.settings.navigate_when_audio_finishes}
- onChange={this.handleSettingsSelect}
- autoComplete="off"
- />
-
- <AudioSelect
- title="On hover"
- name="audio_on_hover_id"
- selected={temporaryTile.settings.audio_on_hover_id}
- onChange={this.handleSettingsSelect}
- />
- </div>
- )}
- </div>
- )
- }
-
- renderMiscForm() {
- const { temporaryTile } = this.props
- return (
- <div>
- <Slider
- title='Opacity'
- name='opacity'
- value={temporaryTile.settings.opacity}
- onChange={this.handleSettingsSelect}
- min={0.0}
- max={1.0}
- step={0.01}
- />
- <Slider
- title='Scale'
- name='scale'
- value={temporaryTile.settings.scale}
- onChange={this.handleSettingsSelect}
- min={0.01}
- max={10.0}
- step={0.01}
- />
- <Slider
- title='Rotation'
- name='rotation'
- value={temporaryTile.settings.rotation}
- onChange={this.handleSettingsSelect}
- min={-180.0}
- max={180.0}
- step={1}
- type='int'
- />
- </div>
- )
- }
-}
-
-const mapStateToProps = state => ({
- graph: state.graph,
- page: state.page,
- tile: state.tile,
- temporaryTile: state.tile.temporaryTile,
-})
-
-const mapDispatchToProps = dispatch => ({
- tileActions: bindActionCreators({ ...tileActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(TileForm)