mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 17:33:14 +01:00
resolve merge
This commit is contained in:
commit
7f82d49278
@ -9,7 +9,7 @@
|
|||||||
<link rel="stylesheet" href="build/css/main.css">
|
<link rel="stylesheet" href="build/css/main.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="main" class="container clear-paddings"></div>
|
<div id="main" class="container"></div>
|
||||||
<div id="modal" class="container"></div>
|
<div id="modal" class="container"></div>
|
||||||
<script src="build/app.js"></script>
|
<script src="build/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -35,4 +35,4 @@ class EditionListActions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default alt.createActions(EditionListActions);
|
export default alt.createActions(EditionListActions);
|
||||||
|
132
js/components/ascribe_media/media_player.js
Normal file
132
js/components/ascribe_media/media_player.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import InjectInHeadMixin from '../../mixins/inject_in_head_mixin';
|
||||||
|
import Panel from 'react-bootstrap/lib/Panel';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the component that implements display-specific functionality.
|
||||||
|
*
|
||||||
|
* ResourceViewer handles the following mimetypes:
|
||||||
|
* - image
|
||||||
|
* - video
|
||||||
|
* - audio
|
||||||
|
* - pdf
|
||||||
|
* - other
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
let Other = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
url: React.PropTypes.string.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let ext = this.props.url.split('.').pop();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel className="media-other">
|
||||||
|
<p className="text-center">
|
||||||
|
.{ext}
|
||||||
|
</p>
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let Image = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
url: React.PropTypes.string.isRequired,
|
||||||
|
preview: React.PropTypes.string.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [InjectInHeadMixin],
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.inject('http://code.jquery.com/jquery-2.1.4.min.js')
|
||||||
|
.then(() =>
|
||||||
|
Promise.all([
|
||||||
|
this.inject('node_modules/shmui/shmui.css'),
|
||||||
|
this.inject('node_modules/shmui/jquery.shmui.js')
|
||||||
|
]).then(() => { window.jQuery('.shmui-ascribe').shmui(); }));
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<img className="shmui-ascribe" src={this.props.preview} data-large-src={this.props.url}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let Video = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
preview: React.PropTypes.string.isRequired,
|
||||||
|
url: React.PropTypes.string.isRequired,
|
||||||
|
extraData: React.PropTypes.array.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [InjectInHeadMixin],
|
||||||
|
|
||||||
|
getInitialState() {
|
||||||
|
return { ready: false };
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.inject('http://code.jquery.com/jquery-2.1.4.min.js')
|
||||||
|
.then(() =>
|
||||||
|
Promise.all([
|
||||||
|
this.inject('https://cdnjs.cloudflare.com/ajax/libs/mediaelement/2.17.0/mediaelement-and-player.min.js'),
|
||||||
|
this.inject('https://cdnjs.cloudflare.com/ajax/libs/mediaelement/2.17.0/mediaelementplayer.min.css')
|
||||||
|
]).then(this.ready));
|
||||||
|
},
|
||||||
|
|
||||||
|
ready() {
|
||||||
|
this.setState({ready: true});
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.ready) {
|
||||||
|
return (
|
||||||
|
<video poster={this.props.preview} controls="controls" preload="none">
|
||||||
|
{this.props.extraData.map((data, i) =>
|
||||||
|
<source key={i} type={'video/' + data.type} src={data.url} />
|
||||||
|
)}
|
||||||
|
</video>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Image src={this.props.preview} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
let resourceMap = {
|
||||||
|
'image': Image,
|
||||||
|
'video': Video,
|
||||||
|
'other': Other
|
||||||
|
};
|
||||||
|
|
||||||
|
let MediaPlayer = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
mimetype: React.PropTypes.oneOf(['image', 'video', 'audio', 'pdf', 'other']).isRequired,
|
||||||
|
preview: React.PropTypes.string.isRequired,
|
||||||
|
url: React.PropTypes.string.isRequired,
|
||||||
|
extraData: React.PropTypes.array
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let Component = resourceMap[this.props.mimetype] || Other;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="ascribe-media-player">
|
||||||
|
<Component preview={this.props.preview}
|
||||||
|
url={this.props.url}
|
||||||
|
extraData={this.props.extraData} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default MediaPlayer;
|
@ -1,42 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import InjectInHeadMixin from '../../mixins/inject_in_head_mixin';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the component that implements display-specific functionality.
|
|
||||||
*
|
|
||||||
* ResourceViewer handles the following mimetypes:
|
|
||||||
* - image
|
|
||||||
* - video
|
|
||||||
* - audio
|
|
||||||
* - pdf
|
|
||||||
* - other
|
|
||||||
*/
|
|
||||||
|
|
||||||
let resourceMap = {
|
|
||||||
'image': 1
|
|
||||||
};
|
|
||||||
|
|
||||||
let ResourceViewer = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
thumbnail: React.PropTypes.string.isRequired,
|
|
||||||
mimetype: React.PropTypes.oneOf(['image', 'video', 'audio', 'pdf', 'other']).isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [InjectInHeadMixin],
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
//this.inject('http://antani.com');
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
resourceviewer {this.props.thumbnail} {this.props.mimetype}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ResourceViewer;
|
|
@ -1,11 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import MediaPlayer from './ascribe_media/media_player';
|
||||||
|
|
||||||
import CollapsibleMixin from 'react-bootstrap/lib/CollapsibleMixin';
|
import CollapsibleMixin from 'react-bootstrap/lib/CollapsibleMixin';
|
||||||
|
import Row from 'react-bootstrap/lib/Row';
|
||||||
|
import Col from 'react-bootstrap/lib/Col';
|
||||||
import Button from 'react-bootstrap/lib/Button';
|
import Button from 'react-bootstrap/lib/Button';
|
||||||
|
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||||
import ResourceViewer from './ascribe_media/resource_viewer';
|
|
||||||
|
|
||||||
import EditionActions from '../actions/edition_actions';
|
import EditionActions from '../actions/edition_actions';
|
||||||
import AclButtonList from './ascribe_buttons/acl_button_list';
|
import AclButtonList from './ascribe_buttons/acl_button_list';
|
||||||
@ -25,6 +27,11 @@ let Edition = React.createClass({
|
|||||||
render() {
|
render() {
|
||||||
let thumbnail = this.props.edition.thumbnail;
|
let thumbnail = this.props.edition.thumbnail;
|
||||||
let mimetype = this.props.edition.digital_work.mime;
|
let mimetype = this.props.edition.digital_work.mime;
|
||||||
|
let extraData = null;
|
||||||
|
|
||||||
|
if (this.props.edition.digital_work.encoding_urls) {
|
||||||
|
extraData = this.props.edition.digital_work.encoding_urls.map(e => { return { url: e.url, type: e.label } });
|
||||||
|
}
|
||||||
|
|
||||||
let bitcoinIdValue = (
|
let bitcoinIdValue = (
|
||||||
<a target="_blank" href={'https://www.blocktrail.com/BTC/address/' + this.props.edition.bitcoin_id}>{this.props.edition.bitcoin_id}</a>
|
<a target="_blank" href={'https://www.blocktrail.com/BTC/address/' + this.props.edition.bitcoin_id}>{this.props.edition.bitcoin_id}</a>
|
||||||
@ -35,12 +42,19 @@ let Edition = React.createClass({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Row>
|
||||||
<div className="col-sm-5">
|
<Col md={7}>
|
||||||
<ResourceViewer thumbnail={thumbnail}
|
<MediaPlayer mimetype={mimetype}
|
||||||
mimetype={mimetype}/>
|
preview={thumbnail}
|
||||||
</div>
|
url={this.props.edition.digital_work.url}
|
||||||
<div className="col-sm-7">
|
extraData={extraData} />
|
||||||
|
<p className="text-center">
|
||||||
|
<Button bsSize="xsmall" href={this.props.edition.digital_work.url} target="_blank">
|
||||||
|
Download <Glyphicon glyph="cloud-download" />
|
||||||
|
</Button>
|
||||||
|
</p>
|
||||||
|
</Col>
|
||||||
|
<Col md={5}>
|
||||||
<EditionHeader edition={this.props.edition}/>
|
<EditionHeader edition={this.props.edition}/>
|
||||||
<EditionSummary
|
<EditionSummary
|
||||||
edition={this.props.edition}
|
edition={this.props.edition}
|
||||||
@ -81,9 +95,8 @@ let Edition = React.createClass({
|
|||||||
Remove this artwork from your list
|
Remove this artwork from your list
|
||||||
</Button>
|
</Button>
|
||||||
</CollapsibleEditionDetails>
|
</CollapsibleEditionDetails>
|
||||||
</div>
|
</Col>
|
||||||
|
</Row>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
let mapAttr = {
|
let mapAttr = {
|
||||||
link: 'href',
|
link: 'href',
|
||||||
source: 'src'
|
script: 'src'
|
||||||
};
|
};
|
||||||
|
|
||||||
let mapExt = {
|
let mapTag = {
|
||||||
js: 'source',
|
js: 'script',
|
||||||
css: 'link'
|
css: 'link'
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,35 +24,46 @@ let InjectInHeadMixin = {
|
|||||||
return document.querySelector(query);
|
return document.querySelector(query);
|
||||||
},
|
},
|
||||||
|
|
||||||
injectTag(tag, src){
|
injectTag(tag, src) {
|
||||||
if (InjectInHeadMixin.isPresent(tag, src)) {
|
let promise = new Promise((resolve, reject) => {
|
||||||
return;
|
if (InjectInHeadMixin.isPresent(tag, src)) {
|
||||||
}
|
resolve();
|
||||||
|
} else {
|
||||||
|
let attr = mapAttr[tag];
|
||||||
|
let element = document.createElement(tag);
|
||||||
|
if (tag === 'script') {
|
||||||
|
element.onload = () => resolve();
|
||||||
|
element.onerror = () => reject();
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
document.head.appendChild(element);
|
||||||
|
element[attr] = src;
|
||||||
|
if (tag === 'link') {
|
||||||
|
element.rel = 'stylesheet';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let attr = mapAttr[tag];
|
return promise;
|
||||||
let element = document.createElement(tag);
|
|
||||||
document.head.appendChild(element);
|
|
||||||
element[attr] = src;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
injectStylesheet(src) {
|
injectStylesheet(src) {
|
||||||
this.injectTag('link', src);
|
return InjectInHeadMixin.injectTag('link', src);
|
||||||
},
|
},
|
||||||
|
|
||||||
injectScript(src) {
|
injectScript(src) {
|
||||||
this.injectTag('source', src);
|
return InjectInHeadMixin.injectTag('source', src);
|
||||||
},
|
},
|
||||||
|
|
||||||
inject(src) {
|
inject(src) {
|
||||||
let ext = src.split('.').pop();
|
let ext = src.split('.').pop();
|
||||||
try {
|
let tag = mapTag[ext];
|
||||||
let tag = mapAttr(src);
|
if (!tag) {
|
||||||
} catch (e) {
|
throw new Error(`Cannot inject ${src} in the DOM, cannot guess the tag name from extension "${ext}". Valid extensions are "js" and "css".`);
|
||||||
throw new Error(`Cannot inject ${src} in the DOM, cannot guess the tag name from extension ${ext}. Valid extensions are "js" and "css".`);
|
|
||||||
}
|
}
|
||||||
// ES6Lint says tag is not defined, pls fix
|
|
||||||
// - Tim
|
return InjectInHeadMixin.injectTag(tag, src);
|
||||||
InjectInHeadMixin.injectTag(tag, src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -42,7 +42,9 @@
|
|||||||
"object-assign": "^2.0.0",
|
"object-assign": "^2.0.0",
|
||||||
"react": "^0.13.2",
|
"react": "^0.13.2",
|
||||||
"react-bootstrap": "~0.22.6",
|
"react-bootstrap": "~0.22.6",
|
||||||
|
"react-datepicker": "~0.8.0",
|
||||||
"react-router": "^0.13.3",
|
"react-router": "^0.13.3",
|
||||||
|
"shmui": "^0.1.0",
|
||||||
"uglifyjs": "^2.4.10",
|
"uglifyjs": "^2.4.10",
|
||||||
"react-datepicker": "~0.8.0"
|
"react-datepicker": "~0.8.0"
|
||||||
},
|
},
|
||||||
|
18
sass/ascribe_media_player.scss
Normal file
18
sass/ascribe_media_player.scss
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
.ascribe-media-player {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-other {
|
||||||
|
font-size: 500%;
|
||||||
|
color: #cccccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@
|
|||||||
@import 'ascribe_piece_list_bulk_modal';
|
@import 'ascribe_piece_list_bulk_modal';
|
||||||
@import 'ascribe_piece_list_toolbar';
|
@import 'ascribe_piece_list_toolbar';
|
||||||
@import 'ascribe_edition';
|
@import 'ascribe_edition';
|
||||||
|
@import 'ascribe_media_player';
|
||||||
@import 'offset_right';
|
@import 'offset_right';
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
|
Loading…
Reference in New Issue
Block a user