added thumbnail input with redux
This commit is contained in:
parent
622b150d1d
commit
ef5c67f293
7 changed files with 97 additions and 116 deletions
|
@ -15,9 +15,9 @@ class Preview extends React.Component {
|
||||||
this.previewFile(this.props.file);
|
this.previewFile(this.props.file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentWillReceiveProps ({ file }) {
|
componentWillReceiveProps (newProps) {
|
||||||
console.log('Preview will receive props');
|
console.log('Preview will receive props', newProps);
|
||||||
this.previewFile(file);
|
this.previewFile(newProps.file);
|
||||||
}
|
}
|
||||||
previewFile (file) {
|
previewFile (file) {
|
||||||
console.log('previewFile', file)
|
console.log('previewFile', file)
|
||||||
|
@ -29,7 +29,7 @@ class Preview extends React.Component {
|
||||||
that.setState({previewSource: previewReader.result});
|
that.setState({previewSource: previewReader.result});
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
that.setState({previewSource: '/assets/img/video_thumb_default.png'});
|
that.setState({previewSource: (this.props.thumbnail || '/assets/img/video_thumb_default.png')});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
|
@ -46,7 +46,8 @@ class Preview extends React.Component {
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
return {
|
return {
|
||||||
file: state.file,
|
file : state.file,
|
||||||
|
thumbnail: state.metadata.thumbnail,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,12 +41,11 @@ class PublishForm extends React.Component {
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="column column--5 column--sml-10" >
|
<div className="column column--5 column--sml-10" >
|
||||||
|
|
||||||
<div className="row row--padded">
|
<div className="row row--padded">
|
||||||
|
|
||||||
<PreviewDropzone />
|
<PreviewDropzone />
|
||||||
{ (this.props.fileType === 'video/mp4') && <PublishThumbnailInput /> }
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="column column--5 column--sml-10 align-content-top">
|
<div className="column column--5 column--sml-10 align-content-top">
|
||||||
<div id="publish-active-area" className="row row--padded">
|
<div id="publish-active-area" className="row row--padded">
|
||||||
|
@ -63,6 +62,8 @@ class PublishForm extends React.Component {
|
||||||
<ChannelSelector />
|
<ChannelSelector />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{ (this.props.fileType === 'video/mp4') && <PublishThumbnailInput /> }
|
||||||
|
|
||||||
<div className="row row--padded row--no-top row--no-bottom row--wide">
|
<div className="row row--padded row--no-top row--no-bottom row--wide">
|
||||||
<PublishMetadataInputs />
|
<PublishMetadataInputs />
|
||||||
</div>
|
</div>
|
||||||
|
@ -89,9 +90,8 @@ class PublishForm extends React.Component {
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
return {
|
return {
|
||||||
fileType : state.file.type,
|
fileType: state.file.type,
|
||||||
claim : state.claim,
|
claim : state.claim,
|
||||||
thumbnail: state.thumbnail,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,14 @@ import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { updateMetadata } from '../actions';
|
import { updateMetadata } from '../actions';
|
||||||
|
|
||||||
|
/*
|
||||||
|
const textarea = document.getElementById('publish-description');
|
||||||
|
const limit = 200;
|
||||||
|
textarea.oninput = () => {
|
||||||
|
textarea.style.height = '';
|
||||||
|
textarea.style.height = Math.min(textarea.scrollHeight, limit) + 'px';
|
||||||
|
*/
|
||||||
|
|
||||||
class MetadataInputs extends React.Component {
|
class MetadataInputs extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
|
@ -1,13 +1,86 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { updateMetadata } from '../actions';
|
||||||
|
|
||||||
class ThumbnailInput extends React.Component {
|
class ThumbnailInput extends React.Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
videoPreviewSrc: null,
|
||||||
|
}
|
||||||
|
this.urlIsAnImage = this.urlIsAnImage.bind(this);
|
||||||
|
this.testImage = this.testImage.bind(this);
|
||||||
|
this.updateVideoThumb = this.updateVideoThumb.bind(this);
|
||||||
|
}
|
||||||
|
urlIsAnImage (url) {
|
||||||
|
return (url.match(/\.(jpeg|jpg|gif|png)$/) != null);
|
||||||
|
}
|
||||||
|
testImage (url, timeoutT) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
const timeout = timeoutT || 5000;
|
||||||
|
let timer;
|
||||||
|
let img = new Image();
|
||||||
|
img.onerror = img.onabort = function () {
|
||||||
|
clearTimeout(timer);
|
||||||
|
reject('error');
|
||||||
|
};
|
||||||
|
img.onload = function () {
|
||||||
|
clearTimeout(timer);
|
||||||
|
resolve('success');
|
||||||
|
};
|
||||||
|
timer = setTimeout(function () {
|
||||||
|
// reset .src to invalid URL so it stops previous
|
||||||
|
// loading, but doesn't trigger new load
|
||||||
|
img.src = '//!!!!/test.jpg';
|
||||||
|
reject('timeout');
|
||||||
|
}, timeout);
|
||||||
|
img.src = url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateVideoThumb (event) {
|
||||||
|
var imageUrl = event.target.value;
|
||||||
|
const that = this;
|
||||||
|
if (this.urlIsAnImage(imageUrl)) {
|
||||||
|
this.testImage(imageUrl, 3000)
|
||||||
|
.then(function (result) {
|
||||||
|
if (result === 'success') {
|
||||||
|
that.props.onThumbnailChange('thumbnail', imageUrl);
|
||||||
|
} else if (result === 'timeout') {
|
||||||
|
console.log('could not resolve the provided thumbnail image url');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log('encountered an error loading thumbnail image url:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="row row--padded row--wide row--no-top" id="publish-thumbnail">
|
||||||
<h3>thumbnail component</h3>
|
<div className="column column--3 column--sml-10">
|
||||||
|
<label className="label">Thumbnail:</label>
|
||||||
|
</div><div className="column column--6 column--sml-10">
|
||||||
|
<div className="input-text--primary">
|
||||||
|
<input type="text" id="claim-thumbnail-input" className="input-text input-text--full-width" placeholder="https://spee.ch/xyz/example.jpg" value={this.props.thumbnail} onInput={this.updateVideoThumb} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ThumbnailInput;
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
thumbnail: state.metadata.thumbnail,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onThumbnailChange: (name, value) => {
|
||||||
|
dispatch(updateMetadata(name, value));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ThumbnailInput);
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
<div class="row row--padded row--no-top row--no-bottom row--wide">
|
|
||||||
<div class="column column--10">
|
|
||||||
<a class="label link--primary" id="publish-details-toggle" href="#" onclick="toggleSection(event)" data-open="false" data-openlabel="[less]" data-closedlabel="[more]" data-slaveelementid="publish-details">[more]</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="publish-details" hidden="true" class="row row--padded row--wide">
|
|
||||||
|
|
||||||
<!-- description input -->
|
|
||||||
<div class="row row--no-top">
|
|
||||||
<div class="column column--3 column--med-10 align-content-top">
|
|
||||||
<label for="publish-license" class="label">Description:</label>
|
|
||||||
</div><div class="column column--7 column--sml-10">
|
|
||||||
<textarea rows="1" id="publish-description" class="textarea textarea--primary textarea--full-width" placeholder="Optional description"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row row--no-top">
|
|
||||||
<div class="column column--3 column--med-10">
|
|
||||||
<label for="publish-license" class="label">License:</label>
|
|
||||||
</div><div class="column column--7 column--sml-10">
|
|
||||||
<select type="text" id="publish-license" class="select select--primary">
|
|
||||||
<option value=" ">Unspecified</option>
|
|
||||||
<option value="Public Domain">Public Domain</option>
|
|
||||||
<option value="Creative Commons">Creative Commons</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row row--no-top">
|
|
||||||
<div class="column column--3">
|
|
||||||
<label for="publish-nsfw" class="label">Mature:</label>
|
|
||||||
</div><div class="column column--7">
|
|
||||||
<input class="input-checkbox" type="checkbox" id="publish-nsfw">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
const textarea = document.getElementById('publish-description');
|
|
||||||
const limit = 200;
|
|
||||||
textarea.oninput = () => {
|
|
||||||
textarea.style.height = '';
|
|
||||||
textarea.style.height = Math.min(textarea.scrollHeight, limit) + 'px';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,56 +1,5 @@
|
||||||
<div class="row row--padded row--wide row--no-top" id="publish-thumbnail" hidden="true">
|
|
||||||
<div class="column column--3 column--sml-10">
|
|
||||||
<label class="label">Thumbnail:</label>
|
|
||||||
</div><div class="column column--6 column--sml-10">
|
|
||||||
<div class="input-text--primary">
|
|
||||||
<input type="text" id="claim-thumbnail-input" class="input-text input-text--full-width" placeholder="https://spee.ch/xyz/example.jpg" value="" oninput="updateVideoThumb(event)">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function urlIsAnImage(url) {
|
|
||||||
return(url.match(/\.(jpeg|jpg|gif|png)$/) != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testImage(url, timeoutT) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
var timeout = timeoutT || 5000;
|
|
||||||
var timer, img = new Image();
|
|
||||||
img.onerror = img.onabort = function () {
|
|
||||||
clearTimeout(timer);
|
|
||||||
reject("error");
|
|
||||||
};
|
|
||||||
img.onload = function () {
|
|
||||||
clearTimeout(timer);
|
|
||||||
resolve("success");
|
|
||||||
};
|
|
||||||
timer = setTimeout(function () {
|
|
||||||
// reset .src to invalid URL so it stops previous
|
|
||||||
// loading, but doesn't trigger new load
|
|
||||||
img.src = "//!!!!/test.jpg";
|
|
||||||
reject("timeout");
|
|
||||||
}, timeout);
|
|
||||||
img.src = url;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateVideoThumb(event){
|
|
||||||
var videoPreview = document.getElementById('asset-preview');
|
|
||||||
var imageUrl = event.target.value;
|
|
||||||
if (urlIsAnImage(imageUrl)){
|
|
||||||
testImage(imageUrl, 3000)
|
|
||||||
.then(function(result) {
|
|
||||||
if (result === 'success'){
|
|
||||||
videoPreview.src = imageUrl;
|
|
||||||
} else if (result === 'timeout') {
|
|
||||||
console.log('could not resolve the provided thumbnail image url');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(function(error) {
|
|
||||||
console.log('encountered an error loading thumbnail image url.')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
Loading…
Reference in a new issue