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
@@ -0,0 +1,65 @@
|
|
1
|
+
pageflow.vr.ConfigurationEditorView = pageflow.ConfigurationEditorView.extend({
|
2
|
+
configure: function() {
|
3
|
+
this.tab('general', function() {
|
4
|
+
this.group('general');
|
5
|
+
|
6
|
+
this.input('additional_title', pageflow.TextInputView);
|
7
|
+
this.input('additional_description', pageflow.TextAreaInputView, {size: 'short'});
|
8
|
+
|
9
|
+
this.input('control_bar_text', pageflow.TextInputView, {
|
10
|
+
placeholder: I18n.t('pageflow.public.vr.start', {
|
11
|
+
locale: pageflow.entry.configuration.get('locale')
|
12
|
+
})
|
13
|
+
});
|
14
|
+
});
|
15
|
+
|
16
|
+
this.tab('files', function() {
|
17
|
+
this.input('video_id', pageflow.FileInputView, {
|
18
|
+
collection: 'video_files',
|
19
|
+
filter: 'with_projection',
|
20
|
+
positioning: false
|
21
|
+
});
|
22
|
+
this.input('autoplay', pageflow.CheckBoxInputView);
|
23
|
+
this.input('start_yaw', pageflow.SliderInputView, {
|
24
|
+
unit: '°',
|
25
|
+
maxValue: 360
|
26
|
+
});
|
27
|
+
this.input('poster_id', pageflow.FileInputView, {
|
28
|
+
collection: 'image_files',
|
29
|
+
filter: 'with_projection',
|
30
|
+
positioning: false
|
31
|
+
});
|
32
|
+
this.input('thumbnail_image_id', pageflow.FileInputView, {
|
33
|
+
collection: 'image_files',
|
34
|
+
positioning: false
|
35
|
+
});
|
36
|
+
});
|
37
|
+
|
38
|
+
this.tab('vr_fallback', function() {
|
39
|
+
this.input('preview_vr_fallback', pageflow.CheckBoxInputView);
|
40
|
+
|
41
|
+
this.group('background', {
|
42
|
+
propertyNamePrefix: 'fallback'
|
43
|
+
});
|
44
|
+
|
45
|
+
this.input('fallback_text', pageflow.TextAreaInputView, {
|
46
|
+
size: 'short'
|
47
|
+
});
|
48
|
+
this.input('fallback_you_tube_url', pageflow.UrlInputView, {
|
49
|
+
permitHttps: true,
|
50
|
+
displayPropertyName: 'display_fallback_you_tube_url',
|
51
|
+
supportedHosts: [
|
52
|
+
'http://youtube.com',
|
53
|
+
'https://youtube.com'
|
54
|
+
]
|
55
|
+
});
|
56
|
+
this.view(pageflow.vr.FallbackPreviewModeView, {
|
57
|
+
model: this.model
|
58
|
+
});
|
59
|
+
});
|
60
|
+
|
61
|
+
this.tab('options', function() {
|
62
|
+
this.group('options');
|
63
|
+
});
|
64
|
+
}
|
65
|
+
});
|
@@ -0,0 +1,73 @@
|
|
1
|
+
//= require_tree ./editor/
|
2
|
+
//= require_self
|
3
|
+
|
4
|
+
pageflow.vr = pageflow.vr || {};
|
5
|
+
|
6
|
+
pageflow.editor.pageTypes.register('vr', {
|
7
|
+
configurationEditorView: pageflow.vr.ConfigurationEditorView,
|
8
|
+
});
|
9
|
+
|
10
|
+
_(['video_files', 'image_files']).each(function(collectionName) {
|
11
|
+
pageflow.editor.fileTypes.modify(collectionName, {
|
12
|
+
configurationEditorInputs: function(model) {
|
13
|
+
var values = ['equirectangular_mono', 'equirectangular_stereo'];
|
14
|
+
var valuesWithAutoDetect = ['auto_detect'].concat(values);
|
15
|
+
|
16
|
+
var options = {
|
17
|
+
includeBlank: true,
|
18
|
+
values: values
|
19
|
+
};
|
20
|
+
|
21
|
+
if (collectionName == 'video_files') {
|
22
|
+
if (model.isNew()) {
|
23
|
+
options = {
|
24
|
+
includeBlank: true,
|
25
|
+
ensureValueDefined: true,
|
26
|
+
values: valuesWithAutoDetect
|
27
|
+
};
|
28
|
+
}
|
29
|
+
else if (!model.isReady() && model.configuration.get('projection') == 'auto_detect') {
|
30
|
+
options = {
|
31
|
+
includeBlank: true,
|
32
|
+
disabled: true,
|
33
|
+
values: valuesWithAutoDetect
|
34
|
+
};
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
return [
|
39
|
+
{
|
40
|
+
name: 'projection',
|
41
|
+
inputView: pageflow.SelectInputView,
|
42
|
+
inputViewOptions: options
|
43
|
+
}
|
44
|
+
];
|
45
|
+
},
|
46
|
+
|
47
|
+
configurationUpdaters: [
|
48
|
+
function(configuration, newAttributes) {
|
49
|
+
if (configuration.get('projection') == 'auto_detect' &&
|
50
|
+
newAttributes.projection != 'auto_detect') {
|
51
|
+
configuration.set('projection', newAttributes.projection);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
],
|
55
|
+
|
56
|
+
confirmUploadTableColumns: [
|
57
|
+
{
|
58
|
+
name: 'projection',
|
59
|
+
cellView: pageflow.EnumTableCellView
|
60
|
+
}
|
61
|
+
],
|
62
|
+
|
63
|
+
filters: [
|
64
|
+
{
|
65
|
+
name: 'with_projection',
|
66
|
+
matches: function(file) {
|
67
|
+
return !!file.configuration.get('projection') &&
|
68
|
+
file.configuration.get('projection') != 'auto_detect';
|
69
|
+
}
|
70
|
+
}
|
71
|
+
]
|
72
|
+
});
|
73
|
+
});
|
@@ -0,0 +1,36 @@
|
|
1
|
+
pageflow.vr.Player.mediaEvents = function(player, context) {
|
2
|
+
function triggerMediaEvent(name, event) {
|
3
|
+
pageflow.events.trigger('media:' + name, {
|
4
|
+
fileName: event.currentSrc,
|
5
|
+
context: context,
|
6
|
+
currentTime: event.currentTime,
|
7
|
+
duration: event.duration,
|
8
|
+
volume: player.volume(),
|
9
|
+
bitrate: getBitrate(event.currentSrc)
|
10
|
+
});
|
11
|
+
}
|
12
|
+
|
13
|
+
player.on('play', function(event) {
|
14
|
+
triggerMediaEvent('play', event);
|
15
|
+
});
|
16
|
+
|
17
|
+
player.on('timeupdate', function(event) {
|
18
|
+
triggerMediaEvent('timeupdate', event);
|
19
|
+
});
|
20
|
+
|
21
|
+
player.on('pause', function(event) {
|
22
|
+
triggerMediaEvent('pause', event);
|
23
|
+
});
|
24
|
+
|
25
|
+
function getBitrate(src) {
|
26
|
+
if (src.match(/4k/)) {
|
27
|
+
return 22000000;
|
28
|
+
}
|
29
|
+
else if (src.match(/fullhd/)) {
|
30
|
+
return 6000000;
|
31
|
+
}
|
32
|
+
else {
|
33
|
+
return 3500000;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
};
|
@@ -0,0 +1,93 @@
|
|
1
|
+
//= require_self
|
2
|
+
//= require ./player/media_events
|
3
|
+
|
4
|
+
pageflow.vr.Player = pageflow.Object.extend({
|
5
|
+
initialize: function(iframe) {
|
6
|
+
this.iframe = iframe;
|
7
|
+
this.cachedVolume = 1;
|
8
|
+
this.cachedPaused = iframe.src.indexOf('no_autoplay=true') >= 0;
|
9
|
+
this.id = getIdParam(iframe.src);
|
10
|
+
|
11
|
+
this.messageListener = this.onMessage.bind(this);
|
12
|
+
|
13
|
+
if (this.id) {
|
14
|
+
window.addEventListener('message', this.messageListener);
|
15
|
+
}
|
16
|
+
},
|
17
|
+
|
18
|
+
dispose: function() {
|
19
|
+
this.off(null, null, null);
|
20
|
+
window.removeEventListener('message', this.messageListener);
|
21
|
+
},
|
22
|
+
|
23
|
+
play: function() {
|
24
|
+
this.cachedPaused = false;
|
25
|
+
this.sendCommand('play');
|
26
|
+
},
|
27
|
+
|
28
|
+
pause: function() {
|
29
|
+
this.cachedPaused = true;
|
30
|
+
this.sendCommand('pause');
|
31
|
+
},
|
32
|
+
|
33
|
+
paused: function() {
|
34
|
+
return this.cachedPaused;
|
35
|
+
},
|
36
|
+
|
37
|
+
volume: function(value) {
|
38
|
+
if (typeof value === 'undefined') {
|
39
|
+
return this.cachedVolume;
|
40
|
+
}
|
41
|
+
else {
|
42
|
+
this.cachedVolume = value;
|
43
|
+
this.sendCommand('volume', Math.max(0, Math.min(1, value)));
|
44
|
+
}
|
45
|
+
},
|
46
|
+
|
47
|
+
enterVRMode: function() {
|
48
|
+
this.sendCommand('enterVRMode');
|
49
|
+
},
|
50
|
+
|
51
|
+
sendCommand: function(name, value) {
|
52
|
+
this.iframe.contentWindow.postMessage({
|
53
|
+
type: 'PlayerCommand',
|
54
|
+
command: name,
|
55
|
+
value: value
|
56
|
+
}, '*');
|
57
|
+
},
|
58
|
+
|
59
|
+
onMessage: function(event) {
|
60
|
+
var message = event.data;
|
61
|
+
|
62
|
+
if (message.type == 'VrViewEvent' &&
|
63
|
+
message.vrViewId == this.id) {
|
64
|
+
|
65
|
+
this.trigger(message.event, message.eventData);
|
66
|
+
}
|
67
|
+
},
|
68
|
+
|
69
|
+
one: function() {
|
70
|
+
this.once.apply(this, arguments);
|
71
|
+
}
|
72
|
+
});
|
73
|
+
|
74
|
+
function getIdParam(url) {
|
75
|
+
var result = url.match(/id=(\d+)/);
|
76
|
+
return result && result[1];
|
77
|
+
}
|
78
|
+
|
79
|
+
pageflow.vr.Player.create = function(iframe, options) {
|
80
|
+
if (!iframe) {
|
81
|
+
return null;
|
82
|
+
}
|
83
|
+
|
84
|
+
var player = new pageflow.vr.Player(iframe);
|
85
|
+
|
86
|
+
pageflow.mediaPlayer.enhance(player, {
|
87
|
+
volumeFading: true
|
88
|
+
});
|
89
|
+
|
90
|
+
pageflow.vr.Player.mediaEvents(player, options.context);
|
91
|
+
|
92
|
+
return player;
|
93
|
+
};
|
@@ -0,0 +1,85 @@
|
|
1
|
+
@include pageflow-page-type("vr");
|
2
|
+
@include pageflow-page-type-pictograms("vr");
|
3
|
+
|
4
|
+
$vr-loading-indicator-color: #fff !default;
|
5
|
+
|
6
|
+
$vr-no-vr-background-color: rgba(17, 17, 17, 0.9) !default;
|
7
|
+
|
8
|
+
$vr-no-vr-icon-color: #555 !default;
|
9
|
+
|
10
|
+
.pageflow_vr-vr_view {
|
11
|
+
pointer-events: all;
|
12
|
+
position: absolute;
|
13
|
+
height: 100%;
|
14
|
+
width: 100%;
|
15
|
+
}
|
16
|
+
|
17
|
+
.pageflow_vr-vr_view-frame {
|
18
|
+
position: absolute;
|
19
|
+
top: 0;
|
20
|
+
left: 0;
|
21
|
+
height: 100%;
|
22
|
+
width: 100%;;
|
23
|
+
}
|
24
|
+
|
25
|
+
.pageflow_vr-page_loading_indicator {
|
26
|
+
position: absolute;
|
27
|
+
top: 50%;
|
28
|
+
left: 50%;
|
29
|
+
@include transform(translate(-50%, -50%));
|
30
|
+
@include transition(opacity 0.5s, visibility 0.5s);
|
31
|
+
}
|
32
|
+
|
33
|
+
.pageflow_vr-page_loading_indicator_icon {
|
34
|
+
display: block;
|
35
|
+
width: 200px;
|
36
|
+
height: 200px;
|
37
|
+
fill: $vr-loading-indicator-color;
|
38
|
+
@include animation(pageflow_vr-blink 3s infinite ease);
|
39
|
+
}
|
40
|
+
|
41
|
+
.pageflow_vr-page_loading_indicator-hidden {
|
42
|
+
opacity: 0;
|
43
|
+
visibility: hidden;
|
44
|
+
pointer-events: none;
|
45
|
+
}
|
46
|
+
|
47
|
+
.pageflow_vr-no_vr_view {
|
48
|
+
margin: 5em auto 0 auto;
|
49
|
+
padding: 20px;
|
50
|
+
background-color: $vr-no-vr-background-color;
|
51
|
+
max-width: 500px;
|
52
|
+
border-radius: 2px;
|
53
|
+
|
54
|
+
a {
|
55
|
+
@extend %anchor;
|
56
|
+
color: $main-color;
|
57
|
+
pointer-events: all;
|
58
|
+
}
|
59
|
+
|
60
|
+
p {
|
61
|
+
width: auto;
|
62
|
+
}
|
63
|
+
|
64
|
+
svg {
|
65
|
+
width: 100px;
|
66
|
+
height: 100px;
|
67
|
+
fill: $vr-no-vr-icon-color;
|
68
|
+
margin: 0 auto 20px auto;
|
69
|
+
display: block;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
@include keyframes(pageflow_vr-blink) {
|
74
|
+
0% {
|
75
|
+
opacity: 0.7;
|
76
|
+
}
|
77
|
+
|
78
|
+
50% {
|
79
|
+
opacity: 0.3;
|
80
|
+
}
|
81
|
+
|
82
|
+
100% {
|
83
|
+
opacity: 0.7;
|
84
|
+
}
|
85
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
html, body {
|
2
|
+
background-color: #000;
|
3
|
+
color: #eee;
|
4
|
+
margin: 0px;
|
5
|
+
padding: 0px;
|
6
|
+
position: fixed;
|
7
|
+
overflow: hidden;
|
8
|
+
top: 0;
|
9
|
+
bottom: 0;
|
10
|
+
left: 0;
|
11
|
+
right: 0;
|
12
|
+
}
|
13
|
+
.dialog {
|
14
|
+
display: none;
|
15
|
+
align-items: center;
|
16
|
+
justify-content: center;
|
17
|
+
font-family: sans-serif;
|
18
|
+
font-size: 170%;
|
19
|
+
position: absolute;
|
20
|
+
width: 100%;
|
21
|
+
height: 100%;
|
22
|
+
background: rgba(255, 255, 255, 0.2);
|
23
|
+
-webkit-user-select: none;
|
24
|
+
-moz-user-select: none;
|
25
|
+
user-select: none;
|
26
|
+
}
|
27
|
+
.dialog.visible {
|
28
|
+
display: flex;
|
29
|
+
}
|
30
|
+
.dialog .wrap {
|
31
|
+
padding: 30px 60px;
|
32
|
+
margin: 20px auto;
|
33
|
+
width: 60%;
|
34
|
+
background: rgba(0, 0, 0, 0.8);
|
35
|
+
border-radius: 5px;
|
36
|
+
}
|
37
|
+
.dialog h1 {
|
38
|
+
margin: 0;
|
39
|
+
}
|
40
|
+
|
41
|
+
a, a:visited {
|
42
|
+
color: skyblue;
|
43
|
+
}
|
44
|
+
|
45
|
+
canvas {
|
46
|
+
cursor: -webkit-grab;
|
47
|
+
}
|
48
|
+
canvas:active {
|
49
|
+
cursor: -webkit-grabbing;
|
50
|
+
}
|
51
|
+
|
52
|
+
.webvr-button:first-of-type,
|
53
|
+
.webvr-button:nth-of-type(2) {
|
54
|
+
display: none !important;
|
55
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<title>VR</title>
|
5
|
+
<meta charset="utf-8">
|
6
|
+
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
7
|
+
<meta name="mobile-web-app-capable" content="yes">
|
8
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
9
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
10
|
+
<link rel="stylesheet" href="/pageflow_vr/vrview.css">
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
<div id="error" class="dialog">
|
14
|
+
<div class="wrap">
|
15
|
+
<h1 class="title">Error</h1>
|
16
|
+
<p class="message">An unknown error occurred.</p>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<script src="/pageflow_vr/vrview.js"></script>
|
21
|
+
</body>
|
22
|
+
</html>
|