pageflow-vr 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.eslintrc +38 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +7 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/README.md +60 -0
- data/Rakefile +9 -0
- data/app/assets/images/pageflow/vr/themes/default/pictograms/sprite.png +0 -0
- data/app/assets/images/pageflow/vr/themes/default/pictograms/wide.png +0 -0
- data/app/assets/images/pageflow/vr_pictogram_small.png +0 -0
- data/app/assets/javascripts/pageflow/vr/browser/vr_view_cardboard_support.js +3 -0
- data/app/assets/javascripts/pageflow/vr/browser/vr_view_support.js +4 -0
- data/app/assets/javascripts/pageflow/vr/components/icons/cardboard.jsx +10 -0
- data/app/assets/javascripts/pageflow/vr/components/icons/play.jsx +11 -0
- data/app/assets/javascripts/pageflow/vr/components/no_vr_view.jsx +34 -0
- data/app/assets/javascripts/pageflow/vr/components/page.jsx +201 -0
- data/app/assets/javascripts/pageflow/vr/components/vr_view.jsx +160 -0
- data/app/assets/javascripts/pageflow/vr/components.js +7 -0
- data/app/assets/javascripts/pageflow/vr/editor/views/configuration_editor_view.js +65 -0
- data/app/assets/javascripts/pageflow/vr/editor/views/fallback_preview_mode_view.js +9 -0
- data/app/assets/javascripts/pageflow/vr/editor.js +73 -0
- data/app/assets/javascripts/pageflow/vr/page_type.js +2 -0
- data/app/assets/javascripts/pageflow/vr/player/media_events.js +36 -0
- data/app/assets/javascripts/pageflow/vr/player.js +93 -0
- data/app/assets/javascripts/pageflow/vr.js +7 -0
- data/app/assets/stylesheets/pageflow/vr/themes/default.scss +85 -0
- data/app/controllers/pageflow/vr/static_files_controller.rb +13 -0
- data/app/views/pageflow/vr/static_files/vrview.css +55 -0
- data/app/views/pageflow/vr/static_files/vrview.html +22 -0
- data/app/views/pageflow/vr/static_files/vrview.js +44415 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config/locales/de.yml +94 -0
- data/config/locales/en.yml +94 -0
- data/config/routes.rb +3 -0
- data/lib/pageflow/vr/engine.rb +14 -0
- data/lib/pageflow/vr/plugin.rb +10 -0
- data/lib/pageflow/vr/projection_auto_detection.rb +42 -0
- data/lib/pageflow/vr/version.rb +5 -0
- data/lib/pageflow-vr.rb +31 -0
- data/pageflow-vr.gemspec +27 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d64b9e546c878f3b8c776389c782effceaa32cd6
|
4
|
+
data.tar.gz: 80b63f6cb35edf377b25376abff3285e62c1632d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fa32ef396c22ac55d0eae8a2b7296e3913fe79467b48b469fc82fc9c0bec2655505f6775b56e9e54a3f8f109688ed7ab5b5d3507a80e1d8c0d77b559cc9dafb0
|
7
|
+
data.tar.gz: ae3b1d9814509dcdace872650f5e938a53995e89c918ddc77e3b342e911fd840ec5030ca0af9008ca4022aa62d49c4c883db34caa64b366b1e1a3f8da1f5f8d7
|
data/.eslintrc
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
{
|
2
|
+
"rules": {
|
3
|
+
"indent": [ 1, 2 ],
|
4
|
+
"quotes": [ 2, "single" ],
|
5
|
+
"linebreak-style": [ 2, "unix" ],
|
6
|
+
"semi": [ 2, "always" ],
|
7
|
+
"no-unused-vars": [ 1, {"vars": "all", "args": "none"} ],
|
8
|
+
"curly": [ 2 ],
|
9
|
+
"no-spaced-func": [ 2 ],
|
10
|
+
"space-before-blocks": [ 2 ],
|
11
|
+
"keyword-spacing": [ 2, { "after": true} ],
|
12
|
+
"no-console": 1,
|
13
|
+
"react/display-name": 0,
|
14
|
+
"react/no-danger": 0,
|
15
|
+
"react/prop-types": [0, { ignore: ['children']}]
|
16
|
+
},
|
17
|
+
"env": {
|
18
|
+
"es6": true,
|
19
|
+
"browser": true,
|
20
|
+
"mocha": true
|
21
|
+
},
|
22
|
+
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
23
|
+
"parserOptions": {
|
24
|
+
"sourceType": "module",
|
25
|
+
"ecmaFeatures": {
|
26
|
+
"jsx": true,
|
27
|
+
"experimentalObjectRestSpread": true,
|
28
|
+
"modules": true
|
29
|
+
}
|
30
|
+
},
|
31
|
+
"plugins": [ "react" ],
|
32
|
+
"globals": {
|
33
|
+
"React": true,
|
34
|
+
"I18n": true,
|
35
|
+
"pageflow": true,
|
36
|
+
"PAGEFLOW_EDITOR": true,
|
37
|
+
}
|
38
|
+
}
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
7
|
+
|
8
|
+
We are committed to making participation in this project a harassment-free
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
12
|
+
|
13
|
+
Examples of unacceptable behavior by participants include:
|
14
|
+
|
15
|
+
* The use of sexualized language or imagery
|
16
|
+
* Personal attacks
|
17
|
+
* Trolling or insulting/derogatory comments
|
18
|
+
* Public or private harassment
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
20
|
+
addresses, without explicit permission
|
21
|
+
* Other unethical or unprofessional conduct
|
22
|
+
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
+
threatening, offensive, or harmful.
|
28
|
+
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
+
Conduct may be permanently removed from the project team.
|
33
|
+
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
35
|
+
when an individual is representing the project or its community.
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
+
reported by contacting a project maintainer at tfischbach@codevise.de. All
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
+
incident.
|
43
|
+
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
+
version 1.3.0, available at
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
+
|
48
|
+
[homepage]: http://contributor-covenant.org
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# Pageflow VR
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/pageflow-vr.svg)](http://badge.fury.io/rb/pageflow-vr)
|
4
|
+
|
5
|
+
Page type to display 360° videos.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
# Gemfile
|
12
|
+
gem 'pageflow-vr'
|
13
|
+
|
14
|
+
Register the plugin:
|
15
|
+
|
16
|
+
# config/initializers/pageflow.rb
|
17
|
+
Pageflow.configure do |config|
|
18
|
+
config.plugin(Pageflow::Vr.plugin)
|
19
|
+
end
|
20
|
+
|
21
|
+
Include javascripts and stylesheets:
|
22
|
+
|
23
|
+
# app/assets/javascripts/components.js
|
24
|
+
//= require "pageflow/vr/components"
|
25
|
+
|
26
|
+
# app/assets/javascripts/pageflow/application.js
|
27
|
+
//= require "pageflow/vr"
|
28
|
+
|
29
|
+
# app/assets/javascripts/pageflow/editor.js
|
30
|
+
//= require pageflow/vr/editor
|
31
|
+
|
32
|
+
# app/assets/stylesheets/pageflow/themes/default.scss
|
33
|
+
@import "pageflow/vr/themes/default";
|
34
|
+
|
35
|
+
Install the routes:
|
36
|
+
|
37
|
+
# config/routes.rb
|
38
|
+
MyPageflow::Application.routes.draw do
|
39
|
+
Pageflow::Vr.routes(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
Execute `bundle install` and restart the application server.
|
43
|
+
|
44
|
+
Now you can enable the page type in your feature settings.
|
45
|
+
|
46
|
+
## Troubleshooting
|
47
|
+
|
48
|
+
If you run into problems while installing the page type, please also
|
49
|
+
refer to the
|
50
|
+
[Troubleshooting](https://github.com/codevise/pageflow/wiki/Troubleshooting)
|
51
|
+
wiki page in the
|
52
|
+
[Pageflow repository](https://github.com/codevise/pageflow). If that
|
53
|
+
doesn't help, consider
|
54
|
+
[filing an issue](https://github.com/codevise/pageflow-vr/issues).
|
55
|
+
|
56
|
+
## Contributing Locales
|
57
|
+
|
58
|
+
Edit the translations directly on the
|
59
|
+
[pageflow-vr](http://www.localeapp.com/projects/public?search=tf/pageflow-vr)
|
60
|
+
locale project.
|
data/Rakefile
ADDED
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,10 @@
|
|
1
|
+
const {SvgIcon} = pageflow.react;
|
2
|
+
|
3
|
+
pageflow.react.iconMapping['pageflow-vr.cardboard'] = function(props) {
|
4
|
+
return (
|
5
|
+
<SvgIcon {...props} viewBoxWidth={24} viewBoxHeight={24}>
|
6
|
+
<path d="M20.74 6H3.21C2.55 6 2 6.57 2 7.28v10.44c0 .7.55 1.28 1.23 1.28h4.79c.52 0 .96-.33 1.14-.79l1.4-3.48c.23-.59.79-1.01 1.44-1.01s1.21.42 1.45 1.01l1.39 3.48c.19.46.63.79 1.11.79h4.79c.71 0 1.26-.57 1.26-1.28V7.28c0-.7-.55-1.28-1.26-1.28zM7.5 14.62c-1.17 0-2.13-.95-2.13-2.12 0-1.17.96-2.13 2.13-2.13 1.18 0 2.12.96 2.12 2.13s-.95 2.12-2.12 2.12zm9 0c-1.17 0-2.13-.95-2.13-2.12 0-1.17.96-2.13 2.13-2.13s2.12.96 2.12 2.13-.95 2.12-2.12 2.12z"/>
|
7
|
+
<path fill="none" d="M0 0h24v24H0V0z"/>
|
8
|
+
</SvgIcon>
|
9
|
+
);
|
10
|
+
};
|
@@ -0,0 +1,11 @@
|
|
1
|
+
const {SvgIcon} = pageflow.react;
|
2
|
+
|
3
|
+
pageflow.react.iconMapping['pageflow-vr.play'] = function(props) {
|
4
|
+
return (
|
5
|
+
<SvgIcon {...props} viewBoxLeft={-10} viewBoxTop={-20} viewBoxWidth={626.65} viewBoxHeight={636.65}>
|
6
|
+
<path d="M308.32,616.65a308.32,308.32,0,0,1-218-526.34,308.32,308.32,0,1,1,436,436A306.3,306.3,0,0,1,308.32,616.65Zm0-580.65A272.32,272.32,0,0,0,115.76,500.88,272.32,272.32,0,0,0,500.88,115.76,270.54,270.54,0,0,0,308.32,36Z"/>
|
7
|
+
<path d="M308.32,456.59c-74.08,0-143.85-14.91-196.46-42-54.3-27.93-84.2-65.68-84.2-106.3S57.56,230,111.86,202c52.61-27.06,122.38-42,196.46-42S452.17,175,504.78,202C559.08,230,589,267.71,589,308.32s-29.9,78.37-84.2,106.3C452.17,441.69,382.4,456.59,308.32,456.59Zm0-280.54c-71.58,0-138.75,14.28-189.14,40.2C70.48,241.31,43.66,274,43.66,308.32s26.82,67,75.52,92.07c50.39,25.92,117.56,40.2,189.14,40.2s138.75-14.28,189.14-40.2c48.7-25.05,75.52-57.75,75.52-92.07s-26.82-67-75.52-92.07C447.07,190.33,379.9,176.06,308.32,176.06Z"/>
|
8
|
+
<path d="M308.32,589c-40.61,0-78.36-29.9-106.3-84.2-27.06-52.61-42-122.38-42-196.46S175,164.47,202,111.86c27.93-54.3,65.68-84.2,106.3-84.2s78.37,29.9,106.3,84.2c27.06,52.61,42,122.38,42,196.46s-14.91,143.85-42,196.46C386.69,559.08,348.94,589,308.32,589Zm0-545.32c-34.32,0-67,26.82-92.07,75.52-25.92,50.39-40.2,117.56-40.2,189.14s14.28,138.75,40.2,189.14C241.31,546.16,274,573,308.32,573s67-26.82,92.07-75.52c25.92-50.39,40.2-117.56,40.2-189.14s-14.28-138.75-40.2-189.14C375.34,70.48,342.64,43.66,308.32,43.66Z"/>
|
9
|
+
</SvgIcon>
|
10
|
+
);
|
11
|
+
};
|
@@ -0,0 +1,34 @@
|
|
1
|
+
(function() {
|
2
|
+
const {Icon} = pageflow.react.components;
|
3
|
+
|
4
|
+
function NoVrView(props) {
|
5
|
+
return (
|
6
|
+
<div className="pageflow_vr-no_vr_view">
|
7
|
+
<Icon name="pageflow-vr.play" />
|
8
|
+
<p dangerouslySetInnerHTML={text(props)} />
|
9
|
+
{renderYouTubeLink(props)}
|
10
|
+
</div>
|
11
|
+
);
|
12
|
+
}
|
13
|
+
|
14
|
+
function text(props) {
|
15
|
+
return {__html: props.text || props.t('pageflow.public.vr.no_vr.text')};
|
16
|
+
}
|
17
|
+
|
18
|
+
function renderYouTubeLink(props) {
|
19
|
+
if (props.youTubeUrl) {
|
20
|
+
return (
|
21
|
+
<a href={props.youTubeUrl} className="pageflow_vr-no_vr_view_link">
|
22
|
+
{props.t('pageflow.public.vr.no_vr.link')}
|
23
|
+
</a>
|
24
|
+
);
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
const {connect, combine} = pageflow.react;
|
29
|
+
const {t} = pageflow.react.selectors;
|
30
|
+
|
31
|
+
pageflow.vr.NoVrView = connect(combine({
|
32
|
+
t
|
33
|
+
}))(NoVrView);
|
34
|
+
}());
|
@@ -0,0 +1,201 @@
|
|
1
|
+
(function() {
|
2
|
+
const {classNames} = pageflow.react;
|
3
|
+
|
4
|
+
const {
|
5
|
+
PageWithInteractiveBackground,
|
6
|
+
PageWrapper, PageContent, PageHeader, PageText, Icon,
|
7
|
+
} = pageflow.react.components;
|
8
|
+
|
9
|
+
const {MediaPageBackground} = pageflow.react.components;
|
10
|
+
|
11
|
+
const {
|
12
|
+
VrView, NoVrView
|
13
|
+
} = pageflow.vr;
|
14
|
+
|
15
|
+
class Page extends React.Component {
|
16
|
+
constructor(props, context) {
|
17
|
+
super(props, context);
|
18
|
+
|
19
|
+
this.state = {
|
20
|
+
isVrViewReady: false,
|
21
|
+
isVrViewPlaying: false
|
22
|
+
};
|
23
|
+
|
24
|
+
this.onVrViewLoading = () => {
|
25
|
+
this.setState({isVrViewReady: false});
|
26
|
+
};
|
27
|
+
|
28
|
+
this.onVrViewReady = () => {
|
29
|
+
this.setState({isVrViewReady: true});
|
30
|
+
};
|
31
|
+
|
32
|
+
this.onEnterBackground = () => {
|
33
|
+
this.setState({isInBackground: true});
|
34
|
+
};
|
35
|
+
|
36
|
+
this.onLeaveBackground = () => {
|
37
|
+
this.setState({isInBackground: false});
|
38
|
+
};
|
39
|
+
|
40
|
+
this.onCardboardButtonClick = () => {
|
41
|
+
this.setState({isCardboardModeRequested: true});
|
42
|
+
};
|
43
|
+
|
44
|
+
this.onExitCardboardMode = () => {
|
45
|
+
this.setState({isCardboardModeRequested: false});
|
46
|
+
};
|
47
|
+
}
|
48
|
+
|
49
|
+
render() {
|
50
|
+
if (!pageflow.browser || !pageflow.browser.has('vr view support') ||
|
51
|
+
(PAGEFLOW_EDITOR && this.props.page.previewVrFallback)) {
|
52
|
+
return this.renderFallbackPage();
|
53
|
+
}
|
54
|
+
else {
|
55
|
+
return this.renderVrViewPage();
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
renderVrViewPage() {
|
60
|
+
const props = this.props;
|
61
|
+
|
62
|
+
return (
|
63
|
+
<PageWithInteractiveBackground page={props.page}
|
64
|
+
playButtonIconName="pageflow-vr.play"
|
65
|
+
defaultControlBarText={props.t('pageflow.public.vr.start')}
|
66
|
+
qualityMenuButtonTitle={props.t('pageflow.public.vr.select_quality')}
|
67
|
+
qualityMenuItems={this.qualityMenuItems()}
|
68
|
+
additionalMenuBarButtons={this.additionalMenuBarButtons()}
|
69
|
+
onAdditionalButtonClick={this.onCardboardButtonClick}
|
70
|
+
onEnterBackground={this.onEnterBackground}
|
71
|
+
onLeaveBackground={this.onLeaveBackground}
|
72
|
+
onQualityMenuItemClick={props.onQualityChange}>
|
73
|
+
|
74
|
+
<VrView id={props.page.permaId}
|
75
|
+
videoId={props.page.videoId}
|
76
|
+
posterId={props.page.posterId}
|
77
|
+
startYaw={props.page.startYaw}
|
78
|
+
quality={this.activeQuality()}
|
79
|
+
isPlaying={props.pageIsActive && (this.state.isInBackground || props.page.autoplay)}
|
80
|
+
isCardboardModeRequested={this.state.isCardboardModeRequested}
|
81
|
+
onLoading={this.onVrViewLoading}
|
82
|
+
onReady={this.onVrViewReady}
|
83
|
+
onExitCardboardMode={this.onExitCardboardMode} />
|
84
|
+
|
85
|
+
{this.renderLoadingIndicator()}
|
86
|
+
</PageWithInteractiveBackground>
|
87
|
+
);
|
88
|
+
}
|
89
|
+
|
90
|
+
renderLoadingIndicator() {
|
91
|
+
const className = classNames('pageflow_vr-page_loading_indicator',
|
92
|
+
{'pageflow_vr-page_loading_indicator-hidden': this.state.isVrViewReady});
|
93
|
+
return (
|
94
|
+
<div className={className}>
|
95
|
+
<Icon name="pageflow-vr.play" className="pageflow_vr-page_loading_indicator_icon" />
|
96
|
+
</div>
|
97
|
+
);
|
98
|
+
}
|
99
|
+
|
100
|
+
renderFallbackPage() {
|
101
|
+
const props = this.props;
|
102
|
+
|
103
|
+
return (
|
104
|
+
<PageWrapper>
|
105
|
+
<MediaPageBackground page={props.page}
|
106
|
+
propertyNamePrefix="fallback" />
|
107
|
+
|
108
|
+
<PageContent>
|
109
|
+
<PageHeader page={props.page} />
|
110
|
+
<PageText page={props.page} />
|
111
|
+
|
112
|
+
<NoVrView text={props.page.fallbackText}
|
113
|
+
youTubeUrl={props.page.fallbackYouTubeUrl} />
|
114
|
+
</PageContent>
|
115
|
+
</PageWrapper>
|
116
|
+
);
|
117
|
+
}
|
118
|
+
|
119
|
+
qualityMenuItems() {
|
120
|
+
const t = this.props.t;
|
121
|
+
const activeQuality = this.activeQuality();
|
122
|
+
|
123
|
+
return this.availableQualitiesInDescendingOrder().map(value => {
|
124
|
+
return {
|
125
|
+
value,
|
126
|
+
label: t(`pageflow.public.vr.video_qualities.${value}`),
|
127
|
+
annotation: t(`pageflow.public.vr.video_quality_annotations.${value}`),
|
128
|
+
active: activeQuality == value,
|
129
|
+
};
|
130
|
+
});
|
131
|
+
}
|
132
|
+
|
133
|
+
additionalMenuBarButtons() {
|
134
|
+
if (!pageflow.browser || !pageflow.browser.has('vr view cardboard support')) {
|
135
|
+
return [];
|
136
|
+
}
|
137
|
+
else {
|
138
|
+
return [
|
139
|
+
{
|
140
|
+
name: 'cardboard',
|
141
|
+
label: this.props.t('pageflow.public.vr.start_cardboard'),
|
142
|
+
iconName: 'pageflow-vr.cardboard'
|
143
|
+
}
|
144
|
+
];
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
activeQuality() {
|
149
|
+
if (this.availableQualitiesInDescendingOrder().indexOf(this.props.requestedQuality) >= 0) {
|
150
|
+
return this.props.requestedQuality;
|
151
|
+
}
|
152
|
+
else {
|
153
|
+
return this.fullHdOrHighQuality();
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
fullHdOrHighQuality() {
|
158
|
+
var qualities = this.availableQualitiesInDescendingOrder();
|
159
|
+
return qualities[1] || qualities[0];
|
160
|
+
}
|
161
|
+
|
162
|
+
availableQualitiesInDescendingOrder() {
|
163
|
+
return ['4k', 'fullhd', 'high'].filter(quality =>
|
164
|
+
this.props.videoFile && this.props.videoFile.urls[quality]
|
165
|
+
);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
const {registerPageType, connectInPage, combine, combineReducers} = pageflow.react;
|
170
|
+
const {pageAttributes, pageAttribute, pageIsActive, t, setting, file} = pageflow.react.selectors;
|
171
|
+
const {updateSetting} = pageflow.react.actions;
|
172
|
+
|
173
|
+
const qualitySetting = 'vr.videoQuality';
|
174
|
+
|
175
|
+
registerPageType('vr', {
|
176
|
+
component: connectInPage(
|
177
|
+
combine({
|
178
|
+
page: pageAttributes(),
|
179
|
+
pageIsActive: pageIsActive(),
|
180
|
+
videoFile: file('videoFiles', {
|
181
|
+
id: pageAttribute('videoId')
|
182
|
+
}),
|
183
|
+
t,
|
184
|
+
requestedQuality: setting({
|
185
|
+
property: qualitySetting
|
186
|
+
})
|
187
|
+
}),
|
188
|
+
{
|
189
|
+
onQualityChange: value => updateSetting({
|
190
|
+
property: qualitySetting,
|
191
|
+
value
|
192
|
+
})
|
193
|
+
}
|
194
|
+
)(Page),
|
195
|
+
|
196
|
+
reduxModules: [
|
197
|
+
pageflow.react.pageWithInteractiveBackgroundReduxModule,
|
198
|
+
pageflow.react.mediaPageBackgroundReduxModule
|
199
|
+
]
|
200
|
+
});
|
201
|
+
}());
|
@@ -0,0 +1,160 @@
|
|
1
|
+
(function() {
|
2
|
+
class VrView extends React.Component {
|
3
|
+
constructor(props, context) {
|
4
|
+
super(props, context);
|
5
|
+
|
6
|
+
this._lastCurrentTime = -1;
|
7
|
+
this._lastSource = null;
|
8
|
+
|
9
|
+
this.bindPlayer = iframe => {
|
10
|
+
if (this.player) {
|
11
|
+
this.player.dispose();
|
12
|
+
}
|
13
|
+
|
14
|
+
this.player = pageflow.vr.Player.create(iframe, {
|
15
|
+
context: this.context.mediaContext
|
16
|
+
});
|
17
|
+
|
18
|
+
if (this.player) {
|
19
|
+
this.player.on({
|
20
|
+
loading: () => {
|
21
|
+
this._lastCurrentTime = 0;
|
22
|
+
|
23
|
+
if (this.props.onLoading) {
|
24
|
+
this.props.onLoading();
|
25
|
+
}
|
26
|
+
},
|
27
|
+
|
28
|
+
ready: () => {
|
29
|
+
if (this.props.onReady) {
|
30
|
+
this.props.onReady();
|
31
|
+
}
|
32
|
+
},
|
33
|
+
|
34
|
+
canplay: () => {
|
35
|
+
if (this.props.isPlaying) {
|
36
|
+
this.player.play();
|
37
|
+
}
|
38
|
+
},
|
39
|
+
|
40
|
+
timeupdate: (event) => {
|
41
|
+
if (this._lastCurrentTime >= 0) {
|
42
|
+
this._lastCurrentTime = event.currentTime;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
});
|
46
|
+
}
|
47
|
+
};
|
48
|
+
}
|
49
|
+
|
50
|
+
componentWillReceiveProps(nextProps) {
|
51
|
+
if (this.props.videoId != nextProps.videoId) {
|
52
|
+
this._lastCurrentTime = -1;
|
53
|
+
}
|
54
|
+
|
55
|
+
if (!this.player) {
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
|
59
|
+
if (nextProps.isPlaying) {
|
60
|
+
// Calling play while already playing is no-op. Since play
|
61
|
+
// might fail when not inside user gesture, always try to play
|
62
|
+
// when prop is set.
|
63
|
+
this.player.play();
|
64
|
+
}
|
65
|
+
else if (this.props.isPlaying && !nextProps.isPlaying) {
|
66
|
+
this.player.fadeOutAndPause(200);
|
67
|
+
}
|
68
|
+
|
69
|
+
if (!this.props.isCardboardModeRequested && nextProps.isCardboardModeRequested) {
|
70
|
+
this.player.enterVRMode();
|
71
|
+
|
72
|
+
// Trigger reset of prop right away. This should listen for events emitted by the iframe instead.
|
73
|
+
if (nextProps.onExitCardboardMode) {
|
74
|
+
setTimeout(() => {
|
75
|
+
nextProps.onExitCardboardMode();
|
76
|
+
}, 100);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
render() {
|
82
|
+
return (
|
83
|
+
<div className="pageflow_vr-vr_view">
|
84
|
+
{this.renderIframeIfPrepared()}
|
85
|
+
</div>
|
86
|
+
);
|
87
|
+
}
|
88
|
+
|
89
|
+
renderIframeIfPrepared() {
|
90
|
+
if (this.props.pageIsPrepared && this.source()) {
|
91
|
+
return this.renderIframe();
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
renderIframe() {
|
96
|
+
return (
|
97
|
+
<iframe ref={this.bindPlayer}
|
98
|
+
className="pageflow_vr-vr_view-frame"
|
99
|
+
allowFullScreen
|
100
|
+
frameBorder="0"
|
101
|
+
src={this.sourceWithUpdatingStartTime()}>
|
102
|
+
</iframe>
|
103
|
+
);
|
104
|
+
}
|
105
|
+
|
106
|
+
sourceWithUpdatingStartTime() {
|
107
|
+
// Only update the start time if the iframe src would change anyway
|
108
|
+
// to prevent reloading the iframe by only changing the start time.
|
109
|
+
if (this.source() != this._lastSource) {
|
110
|
+
this._startTime = this._lastCurrentTime >= 0 ? this._lastCurrentTime : 0;
|
111
|
+
}
|
112
|
+
|
113
|
+
this._lastSource = this.source();
|
114
|
+
return this._lastSource;
|
115
|
+
}
|
116
|
+
|
117
|
+
source() {
|
118
|
+
const props = this.props;
|
119
|
+
|
120
|
+
if (!props.videoFile || !props.videoFile.urls[props.quality]) {
|
121
|
+
return null;
|
122
|
+
}
|
123
|
+
|
124
|
+
return url({
|
125
|
+
id: props.id,
|
126
|
+
video: props.videoFile.urls[props.quality],
|
127
|
+
preview: props.posterFile ? props.posterFile.urls.ultra : props.videoFile.urls.poster_ultra,
|
128
|
+
is_stereo: props.videoFile.projection == 'equirectangular_stereo' ? 'true' : 'false',
|
129
|
+
start_yaw: props.startYaw,
|
130
|
+
start_time: this._startTime,
|
131
|
+
no_autoplay: true
|
132
|
+
});
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
VrView.contextTypes = {
|
137
|
+
mediaContext: React.PropTypes.object
|
138
|
+
};
|
139
|
+
|
140
|
+
function url(params) {
|
141
|
+
const paramsString = Object.keys(params).map((key) =>
|
142
|
+
`${key}=${params[key]}`
|
143
|
+
).join('&');
|
144
|
+
|
145
|
+
return `/pageflow_vr/vrview.html?${paramsString}`;
|
146
|
+
}
|
147
|
+
|
148
|
+
const {connectInPage, combine} = pageflow.react;
|
149
|
+
const {pageIsPrepared, file, prop} = pageflow.react.selectors;
|
150
|
+
|
151
|
+
pageflow.vr.VrView = connectInPage(combine({
|
152
|
+
pageIsPrepared: pageIsPrepared(),
|
153
|
+
videoFile: file('videoFiles', {
|
154
|
+
id: prop('videoId')
|
155
|
+
}),
|
156
|
+
posterFile: file('imageFiles', {
|
157
|
+
id: prop('posterId')
|
158
|
+
})
|
159
|
+
}))(VrView);
|
160
|
+
}());
|