pageflow-vr 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.eslintrc +38 -0
  3. data/.gitignore +10 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +5 -0
  6. data/CHANGELOG.md +7 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +4 -0
  9. data/README.md +60 -0
  10. data/Rakefile +9 -0
  11. data/app/assets/images/pageflow/vr/themes/default/pictograms/sprite.png +0 -0
  12. data/app/assets/images/pageflow/vr/themes/default/pictograms/wide.png +0 -0
  13. data/app/assets/images/pageflow/vr_pictogram_small.png +0 -0
  14. data/app/assets/javascripts/pageflow/vr/browser/vr_view_cardboard_support.js +3 -0
  15. data/app/assets/javascripts/pageflow/vr/browser/vr_view_support.js +4 -0
  16. data/app/assets/javascripts/pageflow/vr/components/icons/cardboard.jsx +10 -0
  17. data/app/assets/javascripts/pageflow/vr/components/icons/play.jsx +11 -0
  18. data/app/assets/javascripts/pageflow/vr/components/no_vr_view.jsx +34 -0
  19. data/app/assets/javascripts/pageflow/vr/components/page.jsx +201 -0
  20. data/app/assets/javascripts/pageflow/vr/components/vr_view.jsx +160 -0
  21. data/app/assets/javascripts/pageflow/vr/components.js +7 -0
  22. data/app/assets/javascripts/pageflow/vr/editor/views/configuration_editor_view.js +65 -0
  23. data/app/assets/javascripts/pageflow/vr/editor/views/fallback_preview_mode_view.js +9 -0
  24. data/app/assets/javascripts/pageflow/vr/editor.js +73 -0
  25. data/app/assets/javascripts/pageflow/vr/page_type.js +2 -0
  26. data/app/assets/javascripts/pageflow/vr/player/media_events.js +36 -0
  27. data/app/assets/javascripts/pageflow/vr/player.js +93 -0
  28. data/app/assets/javascripts/pageflow/vr.js +7 -0
  29. data/app/assets/stylesheets/pageflow/vr/themes/default.scss +85 -0
  30. data/app/controllers/pageflow/vr/static_files_controller.rb +13 -0
  31. data/app/views/pageflow/vr/static_files/vrview.css +55 -0
  32. data/app/views/pageflow/vr/static_files/vrview.html +22 -0
  33. data/app/views/pageflow/vr/static_files/vrview.js +44415 -0
  34. data/bin/console +14 -0
  35. data/bin/setup +8 -0
  36. data/config/locales/de.yml +94 -0
  37. data/config/locales/en.yml +94 -0
  38. data/config/routes.rb +3 -0
  39. data/lib/pageflow/vr/engine.rb +14 -0
  40. data/lib/pageflow/vr/plugin.rb +10 -0
  41. data/lib/pageflow/vr/projection_auto_detection.rb +42 -0
  42. data/lib/pageflow/vr/version.rb +5 -0
  43. data/lib/pageflow-vr.rb +31 -0
  44. data/pageflow-vr.gemspec +27 -0
  45. 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
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.localeapp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.1.0
5
+ before_install: gem install bundler -v 1.12.5
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # CHANGELOG
2
+
3
+ ### Version 1.0.0
4
+
5
+ 2017-08-11
6
+
7
+ Initial release.
@@ -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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pageflow-vr.gemspec
4
+ gemspec
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
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ require 'semmy'
5
+ Semmy::Tasks.install
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ pageflow.browser.feature('vr view cardboard support', function(has) {
2
+ return has('phone platform');
3
+ });
@@ -0,0 +1,4 @@
1
+ pageflow.browser.feature('vr view support', function(has) {
2
+ return !pageflow.browser.agent.matchesMobileSafari() &&
3
+ !pageflow.browser.agent.matchesIEUpTo11();
4
+ });
@@ -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
+ }());
@@ -0,0 +1,7 @@
1
+ //= require_self
2
+ //= require_tree ./components/icons
3
+ //= require ./components/vr_view
4
+ //= require ./components/no_vr_view
5
+ //= require ./components/page
6
+
7
+ pageflow.vr = pageflow.vr || {};