pxvideo_rails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Rakefile +8 -0
- data/Readme.md +64 -0
- data/app/views/pxvideo_rails/_pxvideo_rails.html.erb +51 -0
- data/lib/pxvideo_rails.rb +2 -0
- data/lib/pxvideo_rails/engine.rb +6 -0
- data/lib/pxvideo_rails/railtie.rb +9 -0
- data/lib/pxvideo_rails/view_helpers.rb +15 -0
- data/pxvideo_rails.gemspec +15 -0
- data/vendor/assets/LICENSE.md +27 -0
- data/vendor/assets/images/px-video-sprite.png +0 -0
- data/vendor/assets/javascripts/px-video.js +538 -0
- data/vendor/assets/stylesheets/px-video.css.erb +234 -0
- metadata +55 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 48ec31892cfccac422575bb7c9310f849ca47ff1
|
4
|
+
data.tar.gz: 79cc37782b63f79a7fa8d1bd438d80212890b747
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6a68c34b90f23e08ff4053784ddbac2179c58517968d1be88b74f6696739225fa6fca6764e69f44f02f33ec352381c66a1f83f381186c11e3071e294ddc98d7f
|
7
|
+
data.tar.gz: 410a4e0ee09cccc1a08a7054f3f9ff8d1d8ce93efbf3a0127b51c5b00bd670291719e2ae3832c98a7f80cd85b7feebc000ef9655dc8fa0c52f59ec8f69868233
|
data/.gitignore
ADDED
data/Rakefile
ADDED
data/Readme.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# PX-Video for Asset Pipeline
|
2
|
+
|
3
|
+
html5 video plugin for rails
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Gemfile
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'pxvideo_rails'
|
11
|
+
```
|
12
|
+
|
13
|
+
Add the resources to your application.js file
|
14
|
+
|
15
|
+
```coffeescript
|
16
|
+
# app/assets/javascripts/application.js
|
17
|
+
//= require px-video
|
18
|
+
```
|
19
|
+
|
20
|
+
And that resource to application.css file
|
21
|
+
|
22
|
+
```sass
|
23
|
+
/*
|
24
|
+
*= require px-video
|
25
|
+
*/
|
26
|
+
```
|
27
|
+
|
28
|
+
And to assets.rb add this line
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
# config/initializers/assets.rb
|
32
|
+
Rails.application.config.assets.precompile += %w( px-video-sprite.png )
|
33
|
+
```
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
```erb
|
38
|
+
<%= pxvideo_rails
|
39
|
+
sources: { mp4: "https://www.paypalobjects.com/webstatic/mktg/videos/PayPal_AustinSMB_baseline.mp4" } %>
|
40
|
+
```
|
41
|
+
|
42
|
+
### Properties
|
43
|
+
|
44
|
+
```erb
|
45
|
+
controls: true,
|
46
|
+
setup: "{}",
|
47
|
+
width: "640",
|
48
|
+
height: "480",
|
49
|
+
captions: {en: "https://exampledomain.org/media/captions_PayPal_Austin_en.vtt"},
|
50
|
+
sources: { mp4: "https://www.paypalobjects.com/webstatic/mktg/videos/PayPal_AustinSMB_baseline.mp4" },
|
51
|
+
poster: "https://exampledomain.org/media/poster_PayPal_Austin2.jpg"
|
52
|
+
```
|
53
|
+
|
54
|
+
|
55
|
+
## Based by Accessible HTML5 Video Player
|
56
|
+
|
57
|
+
### Authors
|
58
|
+
- Dennis Lembree, primary developer || [https://github.com/weboverhauls](https://github.com/weboverhauls) || [@dennisl](https://twitter.com/dennisl)
|
59
|
+
- Victor Tsaran, consultation and testing || [https://github.com/vick08](https://github.com/vick08) || [@vick08](https://twitter.com/vick08)
|
60
|
+
- Jason Gabriele, consultation
|
61
|
+
- Tim Resudek, design
|
62
|
+
|
63
|
+
### Copyright and License
|
64
|
+
Copyright 2014, eBay Software Foundation under [the BSD license](LICENSE.md).
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<div class="px-video-container" id="myvid">
|
2
|
+
<div class="px-video-img-captions-container">
|
3
|
+
<div class="px-video-captions hide" aria-hidden="true"></div>
|
4
|
+
<video
|
5
|
+
id="<%=options[:id]%>"
|
6
|
+
<%= "controls" if !!options[:controls] %>
|
7
|
+
width="<%=options[:width]%>"
|
8
|
+
height="<%=options[:height]%>"
|
9
|
+
poster="<%=options[:poster]%>"
|
10
|
+
preload="<%=options[:preload]%>"
|
11
|
+
data-setup="<%= options[:setup] %>"
|
12
|
+
>
|
13
|
+
<!-- source files -->
|
14
|
+
<% if options[:sources] %>
|
15
|
+
<%- options[:sources].each do |type, source| %>
|
16
|
+
<source src="<%= source %>" type='video/<%= type %>' />
|
17
|
+
<%- end %>
|
18
|
+
<%- end %>
|
19
|
+
|
20
|
+
<!-- text track file -->
|
21
|
+
<% if options[:captions] %>
|
22
|
+
<%- options[:captions].each do |lang, caption| %>
|
23
|
+
<track kind="captions" src="<%= caption %>" srclang="<%= lang %>" label="<%= lang %>" />
|
24
|
+
<%- end %>
|
25
|
+
<%- end %>
|
26
|
+
|
27
|
+
<!-- fallback for browsers that don't support the video element -->
|
28
|
+
<div>
|
29
|
+
<% if options[:sources] %>
|
30
|
+
<%- options[:sources].each do |type, source| %>
|
31
|
+
<a href="<%= source %>">
|
32
|
+
<img src="<%=options[:poster]%>" width="<%=options[:width]%>" height="<%=options[:height]%>" alt="download video" />
|
33
|
+
</a>
|
34
|
+
<%- end %>
|
35
|
+
<%- end %>
|
36
|
+
|
37
|
+
</div>
|
38
|
+
</video>
|
39
|
+
</div><!-- end container for captions and video -->
|
40
|
+
<div class="px-video-controls"></div>
|
41
|
+
</div><!-- end video container -->
|
42
|
+
|
43
|
+
<script>
|
44
|
+
// Initialize
|
45
|
+
new InitPxVideo({
|
46
|
+
"videoId": "myvid",
|
47
|
+
"captionsOnDefault": true,
|
48
|
+
"seekInterval": 20,
|
49
|
+
"debug": true
|
50
|
+
});
|
51
|
+
</script>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PxvideoRails
|
2
|
+
module ViewHelpers
|
3
|
+
def pxvideo_rails(*options, &blk)
|
4
|
+
default_options = {
|
5
|
+
controls: true,
|
6
|
+
setup: "{}",
|
7
|
+
preload: "auto",
|
8
|
+
width: 640,
|
9
|
+
height: 480
|
10
|
+
}
|
11
|
+
options = default_options.merge(options.extract_options!)
|
12
|
+
render partial: 'pxvideo_rails/pxvideo_rails', locals: { options: options }, &blk
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'pxvideo_rails'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.date = '2014-09-15'
|
5
|
+
s.summary = "%q{Pxvideo html5 video plugin}"
|
6
|
+
s.description = "%q{HTML5 PxVideo plugin}"
|
7
|
+
s.authors = ["Alexandr Kardakov"]
|
8
|
+
s.email = 'razielsun@gmail.com'
|
9
|
+
s.homepage = ''
|
10
|
+
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (c) 2014, eBay Software Foundation
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice, this
|
11
|
+
list of conditions and the following disclaimer in the documentation and/or
|
12
|
+
other materials provided with the distribution.
|
13
|
+
|
14
|
+
* Neither the name of the eBay nor the names of its
|
15
|
+
subsidiaries or affiliates may be used to endorse or promote products derived from
|
16
|
+
this software without specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
19
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
20
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
22
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
23
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
24
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
25
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
27
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Binary file
|
@@ -0,0 +1,538 @@
|
|
1
|
+
|
2
|
+
function InitPxVideo(options) {
|
3
|
+
|
4
|
+
"use strict";
|
5
|
+
|
6
|
+
// Utilities for caption time codes
|
7
|
+
function video_timecode_min(tc) {
|
8
|
+
var tcpair = [];
|
9
|
+
tcpair = tc.split(' --> ');
|
10
|
+
return videosub_tcsecs(tcpair[0]);
|
11
|
+
}
|
12
|
+
|
13
|
+
function video_timecode_max(tc) {
|
14
|
+
var tcpair = [];
|
15
|
+
tcpair = tc.split(' --> ');
|
16
|
+
return videosub_tcsecs(tcpair[1]);
|
17
|
+
}
|
18
|
+
|
19
|
+
function videosub_tcsecs(tc) {
|
20
|
+
if (tc === null || tc === undefined) {
|
21
|
+
return 0;
|
22
|
+
}
|
23
|
+
else {
|
24
|
+
var tc1 = [],
|
25
|
+
tc2 = [],
|
26
|
+
seconds;
|
27
|
+
tc1 = tc.split(',');
|
28
|
+
tc2 = tc1[0].split(':');
|
29
|
+
seconds = Math.floor(tc2[0]*60*60) + Math.floor(tc2[1]*60) + Math.floor(tc2[2]);
|
30
|
+
return seconds;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
// For "manual" captions, adjust caption position when play time changed (via rewind, clicking progress bar, etc.)
|
35
|
+
function adjustManualCaptions(obj) {
|
36
|
+
obj.subcount = 0;
|
37
|
+
while (video_timecode_max(obj.captions[obj.subcount][0]) < obj.movie.currentTime.toFixed(1)) {
|
38
|
+
obj.subcount++;
|
39
|
+
if (obj.subcount > obj.captions.length-1) {
|
40
|
+
obj.subcount = obj.captions.length-1;
|
41
|
+
break;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
// Display captions container and button (for initialization)
|
47
|
+
function showCaptionContainerAndButton(obj) {
|
48
|
+
obj.captionsBtnContainer.className = "px-video-captions-btn-container pull-left show";
|
49
|
+
if (obj.isCaptionDefault) {
|
50
|
+
obj.captionsContainer.className = "px-video-captions pull-left show";
|
51
|
+
obj.captionsBtn.setAttribute("checked", "checked");
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
// Unfortunately, due to scattered support, browser sniffing is required
|
56
|
+
function browserSniff() {
|
57
|
+
var nVer = navigator.appVersion,
|
58
|
+
nAgt = navigator.userAgent,
|
59
|
+
browserName = navigator.appName,
|
60
|
+
fullVersion = ''+parseFloat(navigator.appVersion),
|
61
|
+
majorVersion = parseInt(navigator.appVersion,10),
|
62
|
+
nameOffset,
|
63
|
+
verOffset,
|
64
|
+
ix;
|
65
|
+
|
66
|
+
// MSIE 11
|
67
|
+
if ((navigator.appVersion.indexOf("Windows NT") !== -1) && (navigator.appVersion.indexOf("rv:11") !== -1)) {
|
68
|
+
browserName = "IE";
|
69
|
+
fullVersion = "11;";
|
70
|
+
}
|
71
|
+
// MSIE
|
72
|
+
else if ((verOffset=nAgt.indexOf("MSIE")) !== -1) {
|
73
|
+
browserName = "IE";
|
74
|
+
fullVersion = nAgt.substring(verOffset+5);
|
75
|
+
}
|
76
|
+
// Chrome
|
77
|
+
else if ((verOffset=nAgt.indexOf("Chrome")) !== -1) {
|
78
|
+
browserName = "Chrome";
|
79
|
+
fullVersion = nAgt.substring(verOffset+7);
|
80
|
+
}
|
81
|
+
// Safari
|
82
|
+
else if ((verOffset=nAgt.indexOf("Safari")) !== -1) {
|
83
|
+
browserName = "Safari";
|
84
|
+
fullVersion = nAgt.substring(verOffset+7);
|
85
|
+
if ((verOffset=nAgt.indexOf("Version")) !== -1) {
|
86
|
+
fullVersion = nAgt.substring(verOffset+8);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
// Firefox
|
90
|
+
else if ((verOffset=nAgt.indexOf("Firefox")) !== -1) {
|
91
|
+
browserName = "Firefox";
|
92
|
+
fullVersion = nAgt.substring(verOffset+8);
|
93
|
+
}
|
94
|
+
// In most other browsers, "name/version" is at the end of userAgent
|
95
|
+
else if ( (nameOffset=nAgt.lastIndexOf(' ')+1) < (verOffset=nAgt.lastIndexOf('/')) ) {
|
96
|
+
browserName = nAgt.substring(nameOffset,verOffset);
|
97
|
+
fullVersion = nAgt.substring(verOffset+1);
|
98
|
+
if (browserName.toLowerCase()==browserName.toUpperCase()) {
|
99
|
+
browserName = navigator.appName;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
// Trim the fullVersion string at semicolon/space if present
|
103
|
+
if ((ix=fullVersion.indexOf(";")) !== -1) {
|
104
|
+
fullVersion=fullVersion.substring(0,ix);
|
105
|
+
}
|
106
|
+
if ((ix=fullVersion.indexOf(" ")) !== -1) {
|
107
|
+
fullVersion=fullVersion.substring(0,ix);
|
108
|
+
}
|
109
|
+
// Get major version
|
110
|
+
majorVersion = parseInt(''+fullVersion,10);
|
111
|
+
if (isNaN(majorVersion)) {
|
112
|
+
fullVersion = ''+parseFloat(navigator.appVersion);
|
113
|
+
majorVersion = parseInt(navigator.appVersion,10);
|
114
|
+
}
|
115
|
+
// Return data
|
116
|
+
return [browserName, majorVersion];
|
117
|
+
}
|
118
|
+
|
119
|
+
// Global variable
|
120
|
+
var obj = {};
|
121
|
+
|
122
|
+
obj.arBrowserInfo = browserSniff();
|
123
|
+
obj.browserName = obj.arBrowserInfo[0];
|
124
|
+
obj.browserMajorVersion = obj.arBrowserInfo[1];
|
125
|
+
|
126
|
+
// If IE8, stop customization (use fallback)
|
127
|
+
// If IE9, stop customization (use native controls)
|
128
|
+
if (obj.browserName === "IE" && (obj.browserMajorVersion === 8 || obj.browserMajorVersion === 9) ) {
|
129
|
+
return false;
|
130
|
+
}
|
131
|
+
|
132
|
+
// If smartphone or tablet, stop customization as video (and captions in latest devices) are handled natively
|
133
|
+
obj.isSmartphoneOrTablet = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
|
134
|
+
if (obj.isSmartphoneOrTablet) {
|
135
|
+
return false;
|
136
|
+
}
|
137
|
+
|
138
|
+
// Set debug mode
|
139
|
+
if (typeof(options.debug)==='undefined') {
|
140
|
+
options.debug = false;
|
141
|
+
}
|
142
|
+
obj.debug = options.debug;
|
143
|
+
|
144
|
+
// Output browser info to log if debug on
|
145
|
+
if (options.debug) {
|
146
|
+
console.log(obj.browserName + " " + obj.browserMajorVersion);
|
147
|
+
}
|
148
|
+
|
149
|
+
// Set up aria-label for Play button with the videoTitle option
|
150
|
+
if ((typeof(options.videoTitle)==='undefined') || (options.videoTitle==="")) {
|
151
|
+
obj.playAriaLabel = "Play";
|
152
|
+
}
|
153
|
+
else {
|
154
|
+
obj.playAriaLabel = "Play video, " + options.videoTitle;
|
155
|
+
}
|
156
|
+
|
157
|
+
// Get the container, video element, and controls container
|
158
|
+
obj.container = document.getElementById(options.videoId);
|
159
|
+
obj.movie = obj.container.getElementsByTagName('video')[0];
|
160
|
+
obj.controls = obj.container.getElementsByClassName('px-video-controls')[0];
|
161
|
+
|
162
|
+
// Remove native video controls
|
163
|
+
obj.movie.removeAttribute("controls");
|
164
|
+
|
165
|
+
// Generate random number for ID/FOR attribute values for controls
|
166
|
+
obj.randomNum = Math.floor(Math.random() * (10000));
|
167
|
+
|
168
|
+
// Insert custom video controls
|
169
|
+
if (options.debug) {
|
170
|
+
console.log("Inserting custom video controls");
|
171
|
+
}
|
172
|
+
obj.controls.innerHTML = '<div class="clearfix">' +
|
173
|
+
'<div class="pull-left">' +
|
174
|
+
'<button class="px-video-restart"><span class="sr-only">Restart</span></button>' +
|
175
|
+
'<button class="px-video-rewind"><span class="sr-only">rewind <span class="px-seconds">10</span> seconds</span></button>' +
|
176
|
+
'<button class="px-video-play" aria-label="'+obj.playAriaLabel+'"><span class="sr-only">Play</span></button>' +
|
177
|
+
'<button class="px-video-pause hide"><span class="sr-only">Pause</span></button>' +
|
178
|
+
'<button class="px-video-forward"><span class="sr-only">forward <span class="px-seconds">10</span> seconds</span></button>' +
|
179
|
+
'</div>' +
|
180
|
+
'<div class="px-video-mute-btn-container pull-left">' +
|
181
|
+
'<input class="px-video-mute sr-only" id="btnMute'+obj.randomNum+'" type="checkbox" />' +
|
182
|
+
'<label id="labelMute'+obj.randomNum+'" for="btnMute'+obj.randomNum+'"><span class="sr-only">Mute</span></label>' +
|
183
|
+
'</div>' +
|
184
|
+
'<div class="pull-left">' +
|
185
|
+
'<label for="volume'+obj.randomNum+'" class="sr-only">Volume:</label><input id="volume'+obj.randomNum+'" class="px-video-volume" type="range" min="0" max="10" value="5" />' +
|
186
|
+
'</div>' +
|
187
|
+
'<div class="px-video-captions-btn-container pull-left hide">' +
|
188
|
+
'<input class="px-video-btnCaptions sr-only" id="btnCaptions'+obj.randomNum+'" type="checkbox" />' +
|
189
|
+
'<label for="btnCaptions'+obj.randomNum+'"><span class="sr-only">Captions</span></label>' +
|
190
|
+
'</div>' +
|
191
|
+
'<div class="px-video-time">' +
|
192
|
+
'<span class="sr-only">time</span> <span class="px-video-duration">00:00</span>' +
|
193
|
+
'</div>' +
|
194
|
+
'</div>' +
|
195
|
+
'<div>' +
|
196
|
+
'<progress class="px-video-progress" max="100" value="0"><span>0</span>% played</progress>' +
|
197
|
+
'</div>';
|
198
|
+
|
199
|
+
// Adjust layout per width of video - container
|
200
|
+
obj.movieWidth = obj.movie.width;
|
201
|
+
if (obj.movieWidth < 360) {
|
202
|
+
obj.movieWidth = 360;
|
203
|
+
}
|
204
|
+
obj.container.setAttribute("style", "width:" + obj.movieWidth + "px");
|
205
|
+
|
206
|
+
// Adjust layout per width of video - controls/mute offset
|
207
|
+
obj.labelMute = document.getElementById("labelMute" + obj.randomNum);
|
208
|
+
obj.labelMuteOffset = obj.movieWidth - 390;
|
209
|
+
if (obj.labelMuteOffset < 0) {
|
210
|
+
obj.labelMuteOffset = 0;
|
211
|
+
}
|
212
|
+
obj.labelMute.setAttribute("style", "margin-left:" + obj.labelMuteOffset + "px");
|
213
|
+
|
214
|
+
// Get URL of caption file if exists
|
215
|
+
var captionSrc = "",
|
216
|
+
kind,
|
217
|
+
children = obj.movie.childNodes;
|
218
|
+
|
219
|
+
for (var i = 0; i < children.length; i++) {
|
220
|
+
if (children[i].nodeName.toLowerCase() === 'track') {
|
221
|
+
kind = children[i].getAttribute('kind');
|
222
|
+
if (kind === 'captions') {
|
223
|
+
captionSrc = children[i].getAttribute('src');
|
224
|
+
}
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
// Record if caption file exists or not
|
229
|
+
obj.captionExists = true;
|
230
|
+
if (captionSrc === "") {
|
231
|
+
obj.captionExists = false;
|
232
|
+
if (options.debug) {
|
233
|
+
console.log("No caption track found.");
|
234
|
+
}
|
235
|
+
}
|
236
|
+
else {
|
237
|
+
if (options.debug) {
|
238
|
+
console.log("Caption track found; URI: " + captionSrc);
|
239
|
+
}
|
240
|
+
}
|
241
|
+
|
242
|
+
// Set captions on/off - on by default
|
243
|
+
if (typeof(options.captionsOnDefault) === 'undefined') {
|
244
|
+
options.captionsOnDefault = true;
|
245
|
+
}
|
246
|
+
obj.isCaptionDefault = options.captionsOnDefault;
|
247
|
+
|
248
|
+
// Number of seconds for rewind and forward buttons
|
249
|
+
if (typeof(options.seekInterval) === 'undefined') {
|
250
|
+
options.seekInterval = 10;
|
251
|
+
}
|
252
|
+
obj.seekInterval = options.seekInterval;
|
253
|
+
|
254
|
+
// Get the elements for the controls
|
255
|
+
obj.btnPlay = obj.container.getElementsByClassName('px-video-play')[0];
|
256
|
+
obj.btnPause = obj.container.getElementsByClassName('px-video-pause')[0];
|
257
|
+
obj.btnRestart = obj.container.getElementsByClassName('px-video-restart')[0];
|
258
|
+
obj.btnRewind = obj.container.getElementsByClassName('px-video-rewind')[0];
|
259
|
+
obj.btnForward = obj.container.getElementsByClassName('px-video-forward')[0];
|
260
|
+
obj.btnVolume = obj.container.getElementsByClassName('px-video-volume')[0];
|
261
|
+
obj.btnMute = obj.container.getElementsByClassName('px-video-mute')[0];
|
262
|
+
obj.progressBar = obj.container.getElementsByClassName('px-video-progress')[0];
|
263
|
+
obj.progressBarSpan = obj.progressBar.getElementsByTagName('span')[0];
|
264
|
+
obj.captionsContainer = obj.container.getElementsByClassName('px-video-captions')[0];
|
265
|
+
obj.captionsBtn = obj.container.getElementsByClassName('px-video-btnCaptions')[0];
|
266
|
+
obj.captionsBtnContainer = obj.container.getElementsByClassName('px-video-captions-btn-container')[0];
|
267
|
+
obj.duration = obj.container.getElementsByClassName('px-video-duration')[0];
|
268
|
+
obj.txtSeconds = obj.container.getElementsByClassName('px-seconds');
|
269
|
+
|
270
|
+
// Update number of seconds in rewind and fast forward buttons
|
271
|
+
obj.txtSeconds[0].innerHTML = obj.seekInterval;
|
272
|
+
obj.txtSeconds[1].innerHTML = obj.seekInterval;
|
273
|
+
|
274
|
+
// Determine if HTML5 textTracks is supported (for captions)
|
275
|
+
obj.isTextTracks = false;
|
276
|
+
if (obj.movie.textTracks) {
|
277
|
+
obj.isTextTracks = true;
|
278
|
+
}
|
279
|
+
|
280
|
+
// Play
|
281
|
+
obj.btnPlay.addEventListener('click', function() {
|
282
|
+
obj.movie.play();
|
283
|
+
obj.btnPlay.className = "px-video-play hide";
|
284
|
+
obj.btnPause.className = "px-video-pause px-video-show-inline";
|
285
|
+
obj.btnPause.focus();
|
286
|
+
}, false);
|
287
|
+
|
288
|
+
// Pause
|
289
|
+
obj.btnPause.addEventListener('click', function() {
|
290
|
+
obj.movie.pause();
|
291
|
+
obj.btnPlay.className = "px-video-play px-video-show-inline";
|
292
|
+
obj.btnPause.className = "px-video-pause hide";
|
293
|
+
obj.btnPlay.focus();
|
294
|
+
}, false);
|
295
|
+
|
296
|
+
// Restart
|
297
|
+
obj.btnRestart.addEventListener('click', function() {
|
298
|
+
// Move to beginning
|
299
|
+
obj.movie.currentTime = 0;
|
300
|
+
|
301
|
+
// Special handling for "manual" captions
|
302
|
+
if (!obj.isTextTracks) {
|
303
|
+
obj.subcount = 0;
|
304
|
+
}
|
305
|
+
|
306
|
+
// Play and ensure the play button is in correct state
|
307
|
+
obj.movie.play();
|
308
|
+
obj.btnPlay.className = "px-video-play hide";
|
309
|
+
obj.btnPause.className = "px-video-pause px-video-show-inline";
|
310
|
+
|
311
|
+
}, false);
|
312
|
+
|
313
|
+
// Rewind
|
314
|
+
obj.btnRewind.addEventListener('click', function() {
|
315
|
+
var targetTime = obj.movie.currentTime - obj.seekInterval;
|
316
|
+
if (targetTime < 0) {
|
317
|
+
obj.movie.currentTime = 0;
|
318
|
+
}
|
319
|
+
else {
|
320
|
+
obj.movie.currentTime = targetTime;
|
321
|
+
}
|
322
|
+
// Special handling for "manual" captions
|
323
|
+
if (!obj.isTextTracks) {
|
324
|
+
adjustManualCaptions(obj);
|
325
|
+
}
|
326
|
+
}, false);
|
327
|
+
|
328
|
+
// Fast forward
|
329
|
+
obj.btnForward.addEventListener('click', function() {
|
330
|
+
var targetTime = obj.movie.currentTime + obj.seekInterval;
|
331
|
+
if (targetTime > obj.movie.duration) {
|
332
|
+
obj.movie.currentTime = obj.movie.duration;
|
333
|
+
}
|
334
|
+
else {
|
335
|
+
obj.movie.currentTime = targetTime;
|
336
|
+
}
|
337
|
+
// Special handling for "manual" captions
|
338
|
+
if (!obj.isTextTracks) {
|
339
|
+
adjustManualCaptions(obj);
|
340
|
+
}
|
341
|
+
}, false);
|
342
|
+
|
343
|
+
// Get the HTML5 range input element and append audio volume adjustment on change
|
344
|
+
obj.btnVolume.addEventListener('change', function() {
|
345
|
+
obj.movie.volume = parseFloat(this.value / 10);
|
346
|
+
}, false);
|
347
|
+
|
348
|
+
// Mute
|
349
|
+
obj.btnMute.addEventListener('click', function() {
|
350
|
+
if (obj.movie.muted === true) {
|
351
|
+
obj.movie.muted = false;
|
352
|
+
}
|
353
|
+
else {
|
354
|
+
obj.movie.muted = true;
|
355
|
+
}
|
356
|
+
}, false);
|
357
|
+
|
358
|
+
// Duration
|
359
|
+
obj.movie.addEventListener("timeupdate", function() {
|
360
|
+
obj.secs = parseInt(obj.movie.currentTime % 60);
|
361
|
+
obj.mins = parseInt((obj.movie.currentTime / 60) % 60);
|
362
|
+
|
363
|
+
// Ensure it's two digits. For example, 03 rather than 3.
|
364
|
+
obj.secs = ("0" + obj.secs).slice(-2);
|
365
|
+
obj.mins = ("0" + obj.mins).slice(-2);
|
366
|
+
|
367
|
+
// Render
|
368
|
+
obj.duration.innerHTML = obj.mins + ':' + obj.secs;
|
369
|
+
}, false);
|
370
|
+
|
371
|
+
// Progress bar
|
372
|
+
obj.movie.addEventListener('timeupdate', function() {
|
373
|
+
obj.percent = Math.floor((100 / obj.movie.duration) * obj.movie.currentTime);
|
374
|
+
if (obj.percent > 0) {
|
375
|
+
obj.progressBar.value = obj.percent;
|
376
|
+
obj.progressBarSpan.innerHTML = obj.percent;
|
377
|
+
}
|
378
|
+
}, false);
|
379
|
+
|
380
|
+
// Skip when clicking progress bar
|
381
|
+
obj.progressBar.addEventListener('click', function(e) {
|
382
|
+
obj.pos = (e.pageX - this.offsetLeft) / this.offsetWidth;
|
383
|
+
obj.movie.currentTime = obj.pos * obj.movie.duration;
|
384
|
+
|
385
|
+
// Special handling for "manual" captions
|
386
|
+
if (!obj.isTextTracks) {
|
387
|
+
adjustManualCaptions(obj);
|
388
|
+
}
|
389
|
+
});
|
390
|
+
|
391
|
+
// Clear captions at end of video
|
392
|
+
obj.movie.addEventListener('ended', function() {
|
393
|
+
obj.captionsContainer.innerHTML = "";
|
394
|
+
});
|
395
|
+
|
396
|
+
// ***
|
397
|
+
// Captions
|
398
|
+
// ***
|
399
|
+
|
400
|
+
// Toggle display of captions via captions button
|
401
|
+
obj.captionsBtn.addEventListener('click', function() {
|
402
|
+
if (this.checked) {
|
403
|
+
obj.captionsContainer.className = "px-video-captions show";
|
404
|
+
} else {
|
405
|
+
obj.captionsContainer.className = "px-video-captions hide";
|
406
|
+
}
|
407
|
+
}, false);
|
408
|
+
|
409
|
+
// If no caption file exists, hide container for caption text
|
410
|
+
if (!obj.captionExists) {
|
411
|
+
obj.captionsContainer.className = "px-video-captions hide";
|
412
|
+
}
|
413
|
+
|
414
|
+
// If caption file exists, process captions
|
415
|
+
else {
|
416
|
+
|
417
|
+
// If IE 10/11 or Firefox 31 or Safari 7, don't use native captioning (still doesn't work although they claim it's now supported)
|
418
|
+
if ((obj.browserName==="IE" && obj.browserMajorVersion===10) ||
|
419
|
+
(obj.browserName==="IE" && obj.browserMajorVersion===11) ||
|
420
|
+
(obj.browserName==="Firefox" && obj.browserMajorVersion>=31) ||
|
421
|
+
(obj.browserName==="Safari" && obj.browserMajorVersion===7)) {
|
422
|
+
if (options.debug) {
|
423
|
+
console.log("Detected IE 10/11 or Firefox 31+ or Safari 7");
|
424
|
+
}
|
425
|
+
// set to false so skips to 'manual' captioning
|
426
|
+
obj.isTextTracks = false;
|
427
|
+
|
428
|
+
// turn off native caption rendering to avoid double captions [doesn't work in Safari 7; see patch below]
|
429
|
+
var track = {};
|
430
|
+
var tracks = obj.movie.textTracks;
|
431
|
+
for (var j=0; j < tracks.length; j++) {
|
432
|
+
track = obj.movie.textTracks[j];
|
433
|
+
track.mode = "hidden";
|
434
|
+
}
|
435
|
+
}
|
436
|
+
|
437
|
+
// Rendering caption tracks - native support required - http://caniuse.com/webvtt
|
438
|
+
if (obj.isTextTracks) {
|
439
|
+
if (options.debug) {
|
440
|
+
console.log("textTracks supported");
|
441
|
+
}
|
442
|
+
showCaptionContainerAndButton(obj);
|
443
|
+
|
444
|
+
var track = {};
|
445
|
+
var tracks = obj.movie.textTracks;
|
446
|
+
for (var j=0; j < tracks.length; j++) {
|
447
|
+
track = obj.movie.textTracks[j];
|
448
|
+
track.mode = "hidden";
|
449
|
+
if (track.kind === "captions") {
|
450
|
+
track.addEventListener("cuechange",function() {
|
451
|
+
if (this.activeCues[0]) {
|
452
|
+
if (this.activeCues[0].hasOwnProperty("text")) {
|
453
|
+
obj.captionsContainer.innerHTML = this.activeCues[0].text;
|
454
|
+
}
|
455
|
+
}
|
456
|
+
},false);
|
457
|
+
}
|
458
|
+
}
|
459
|
+
}
|
460
|
+
// Caption tracks not natively supported
|
461
|
+
else {
|
462
|
+
if (options.debug) {
|
463
|
+
console.log("textTracks not supported so rendering captions 'manually'");
|
464
|
+
}
|
465
|
+
showCaptionContainerAndButton(obj);
|
466
|
+
|
467
|
+
// Render captions from array at apppropriate time
|
468
|
+
obj.currentCaption = '';
|
469
|
+
obj.subcount = 0;
|
470
|
+
obj.captions = [];
|
471
|
+
|
472
|
+
obj.movie.addEventListener('timeupdate', function() {
|
473
|
+
// Check if the next caption is in the current time range
|
474
|
+
if (obj.movie.currentTime.toFixed(1) > video_timecode_min(obj.captions[obj.subcount][0]) &&
|
475
|
+
obj.movie.currentTime.toFixed(1) < video_timecode_max(obj.captions[obj.subcount][0])) {
|
476
|
+
obj.currentCaption = obj.captions[obj.subcount][1];
|
477
|
+
}
|
478
|
+
// Is there a next timecode?
|
479
|
+
if (obj.movie.currentTime.toFixed(1) > video_timecode_max(obj.captions[obj.subcount][0]) &&
|
480
|
+
obj.subcount < (obj.captions.length-1)) {
|
481
|
+
obj.subcount++;
|
482
|
+
}
|
483
|
+
// Render the caption
|
484
|
+
obj.captionsContainer.innerHTML = obj.currentCaption;
|
485
|
+
}, false);
|
486
|
+
|
487
|
+
if (captionSrc != "") {
|
488
|
+
// Create XMLHttpRequest object
|
489
|
+
var xhr;
|
490
|
+
if (window.XMLHttpRequest) {
|
491
|
+
xhr = new XMLHttpRequest();
|
492
|
+
} else if (window.ActiveXObject) { // IE8
|
493
|
+
xhr = new ActiveXObject("Microsoft.XMLHTTP");
|
494
|
+
}
|
495
|
+
xhr.onreadystatechange = function() {
|
496
|
+
if (xhr.readyState === 4) {
|
497
|
+
if (xhr.status === 200) {
|
498
|
+
if (options.debug) {
|
499
|
+
console.log("xhr = 200");
|
500
|
+
}
|
501
|
+
|
502
|
+
obj.captions = [];
|
503
|
+
var records = [],
|
504
|
+
record,
|
505
|
+
req = xhr.responseText;
|
506
|
+
records = req.split('\n\n');
|
507
|
+
for (var r=0; r < records.length; r++) {
|
508
|
+
record = records[r];
|
509
|
+
obj.captions[r] = [];
|
510
|
+
obj.captions[r] = record.split('\n');
|
511
|
+
}
|
512
|
+
// Remove first element ("VTT")
|
513
|
+
obj.captions.shift();
|
514
|
+
|
515
|
+
if (options.debug) {
|
516
|
+
console.log('Successfully loaded the caption file via ajax.');
|
517
|
+
}
|
518
|
+
} else {
|
519
|
+
if (options.debug) {
|
520
|
+
console.log('There was a problem loading the caption file via ajax.');
|
521
|
+
}
|
522
|
+
}
|
523
|
+
}
|
524
|
+
}
|
525
|
+
xhr.open("get", captionSrc, true);
|
526
|
+
xhr.send();
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
// If Safari 7, removing track from DOM [see 'turn off native caption rendering' above]
|
531
|
+
if (obj.browserName === "Safari" && obj.browserMajorVersion === 7) {
|
532
|
+
console.log("Safari 7 detected; removing track from DOM");
|
533
|
+
var tracks = obj.movie.getElementsByTagName("track");
|
534
|
+
obj.movie.removeChild(tracks[0]);
|
535
|
+
}
|
536
|
+
|
537
|
+
}
|
538
|
+
};
|
@@ -0,0 +1,234 @@
|
|
1
|
+
|
2
|
+
/* utilities */
|
3
|
+
.pull-left {
|
4
|
+
float: left;
|
5
|
+
}
|
6
|
+
.sr-only {
|
7
|
+
position: absolute !important;
|
8
|
+
clip: rect(1px, 1px, 1px, 1px);
|
9
|
+
padding: 0 !important;
|
10
|
+
border: 0 !important;
|
11
|
+
height: 1px !important;
|
12
|
+
width: 1px !important;
|
13
|
+
overflow: hidden;
|
14
|
+
}
|
15
|
+
.hide {
|
16
|
+
display: none;
|
17
|
+
}
|
18
|
+
.show-inline {
|
19
|
+
display: inline-block;
|
20
|
+
}
|
21
|
+
|
22
|
+
/* containers */
|
23
|
+
.px-video-img-captions-container * {
|
24
|
+
box-sizing: border-box;
|
25
|
+
}
|
26
|
+
|
27
|
+
.px-video-img-captions-container {
|
28
|
+
position: relative;
|
29
|
+
}
|
30
|
+
|
31
|
+
/* progress indicator */
|
32
|
+
.px-video-progress {
|
33
|
+
width: 100%;
|
34
|
+
height: 10px;
|
35
|
+
}
|
36
|
+
.px-video-progress[value] {
|
37
|
+
/* Reset the default appearance */
|
38
|
+
-webkit-appearance: none;
|
39
|
+
border: none;
|
40
|
+
}
|
41
|
+
.px-video-progress[value]::-webkit-progress-bar {
|
42
|
+
background-color: #E6E6E6;
|
43
|
+
}
|
44
|
+
.px-video-progress[value]::-webkit-progress-value {
|
45
|
+
background-color: #009CDF;
|
46
|
+
}
|
47
|
+
|
48
|
+
/* time */
|
49
|
+
.px-video-time {
|
50
|
+
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
51
|
+
float: right;
|
52
|
+
margin-top: 2px;
|
53
|
+
font-size: 14px;
|
54
|
+
}
|
55
|
+
|
56
|
+
/* caption area */
|
57
|
+
.px-video-captions {
|
58
|
+
position: absolute;
|
59
|
+
top: 0;
|
60
|
+
left: 0;
|
61
|
+
width: 100%;
|
62
|
+
padding: .5em;
|
63
|
+
min-height: 2.5em;
|
64
|
+
background-color: #000;
|
65
|
+
color: #fff;
|
66
|
+
font-size: 1.1em;
|
67
|
+
text-align: center;
|
68
|
+
opacity: 0.75;
|
69
|
+
}
|
70
|
+
|
71
|
+
/* buttons */
|
72
|
+
.px-video-controls button {
|
73
|
+
border: 1px #fff solid;
|
74
|
+
background: transparent;
|
75
|
+
padding: 0;
|
76
|
+
margin: 0 5px;
|
77
|
+
width: 25px;
|
78
|
+
height: 20px;
|
79
|
+
overflow: hidden;
|
80
|
+
background: no-repeat url('<%= asset_path('px-video-sprite.png') %>');
|
81
|
+
}
|
82
|
+
.px-video-controls button:focus {
|
83
|
+
border: 1px #999 dotted;
|
84
|
+
outline: none;
|
85
|
+
}
|
86
|
+
.px-video-controls button {
|
87
|
+
cursor: pointer;
|
88
|
+
}
|
89
|
+
|
90
|
+
/* restart button */
|
91
|
+
.px-video-controls button.px-video-restart {
|
92
|
+
background-position: -9px -333px;
|
93
|
+
}
|
94
|
+
.px-video-controls button.px-video-restart:hover,
|
95
|
+
.px-video-controls button.px-video-restart:focus {
|
96
|
+
background-position: -9px -297px;
|
97
|
+
}
|
98
|
+
|
99
|
+
/* rewind button */
|
100
|
+
.px-video-controls button.px-video-rewind {
|
101
|
+
background-position: -11px -189px;
|
102
|
+
}
|
103
|
+
.px-video-controls button.px-video-rewind:hover,
|
104
|
+
.px-video-controls button.px-video-rewind:focus {
|
105
|
+
background-position: -11px -153px;
|
106
|
+
}
|
107
|
+
|
108
|
+
/* play button */
|
109
|
+
.px-video-controls button.px-video-play {
|
110
|
+
background-position: -11px -45px;
|
111
|
+
}
|
112
|
+
.px-video-controls button.px-video-play:hover,
|
113
|
+
.px-video-controls button.px-video-play:focus {
|
114
|
+
background-position: -11px -9px;
|
115
|
+
}
|
116
|
+
|
117
|
+
/* pause button */
|
118
|
+
.px-video-controls button.px-video-pause {
|
119
|
+
background-position: -11px -117px;
|
120
|
+
}
|
121
|
+
.px-video-controls button.px-video-pause:hover,
|
122
|
+
.px-video-controls button.px-video-pause:focus {
|
123
|
+
background-position: -11px -81px;
|
124
|
+
}
|
125
|
+
|
126
|
+
/* forward button */
|
127
|
+
.px-video-controls button.px-video-forward {
|
128
|
+
background-position: -13px -261px;
|
129
|
+
}
|
130
|
+
.px-video-controls button.px-video-forward:hover,
|
131
|
+
.px-video-controls button.px-video-forward:focus {
|
132
|
+
background-position: -13px -225px;
|
133
|
+
}
|
134
|
+
|
135
|
+
/* captions button */
|
136
|
+
.px-video-captions-btn-container label {
|
137
|
+
display: inline-block;
|
138
|
+
width: 25px;
|
139
|
+
height: 20px;
|
140
|
+
margin-left: 25px;
|
141
|
+
background: no-repeat url('<%= asset_path('px-video-sprite.png') %>');
|
142
|
+
background-position: -6px -835px;
|
143
|
+
}
|
144
|
+
.px-video-captions-btn-container input[type="checkbox"]:focus+label {
|
145
|
+
outline: 1px #999 dotted;
|
146
|
+
background-position: -6px -799px;
|
147
|
+
}
|
148
|
+
.px-video-captions-btn-container input[type="checkbox"]:hover+label {
|
149
|
+
background-position: -6px -799px;
|
150
|
+
cursor: pointer;
|
151
|
+
}
|
152
|
+
.px-video-captions-btn-container input[type="checkbox"]:focus+label {
|
153
|
+
outline: 1px #999 dotted;
|
154
|
+
background-position: -6px -799px;
|
155
|
+
}
|
156
|
+
.px-video-captions-btn-container input[type="checkbox"]:checked+label {
|
157
|
+
background-position: -6px -871px;
|
158
|
+
}
|
159
|
+
|
160
|
+
/* mute button */
|
161
|
+
.px-video-mute-btn-container label {
|
162
|
+
display: inline-block;
|
163
|
+
width: 25px;
|
164
|
+
height: 20px;
|
165
|
+
margin-left: 240px;
|
166
|
+
margin-top: 2px;
|
167
|
+
background: no-repeat url('<%= asset_path('px-video-sprite.png') %>');
|
168
|
+
background-position: -6px -476px;
|
169
|
+
}
|
170
|
+
.px-video-mute-btn-container input[type="checkbox"]:focus+label {
|
171
|
+
outline: 1px #999 dotted;
|
172
|
+
background-position: -6px -440px;
|
173
|
+
}
|
174
|
+
.px-video-mute-btn-container input[type="checkbox"]:hover+label {
|
175
|
+
background-position: -6px -440px;
|
176
|
+
cursor: pointer;
|
177
|
+
}
|
178
|
+
.px-video-mute-btn-container input[type="checkbox"]:focus+label {
|
179
|
+
outline: 1px #999 dotted;
|
180
|
+
background-position: -6px -440px;
|
181
|
+
}
|
182
|
+
/* checked state of mute button */
|
183
|
+
.px-video-mute-btn-container input[type="checkbox"]:checked+label {
|
184
|
+
background-position: -6px -692px;
|
185
|
+
}
|
186
|
+
.px-video-mute-btn-container input[type="checkbox"]:checked:hover+label,
|
187
|
+
.px-video-mute-btn-container input[type="checkbox"]:checked:focus+label {
|
188
|
+
background-position: -6px -656px;
|
189
|
+
}
|
190
|
+
|
191
|
+
/* volume range input */
|
192
|
+
.px-video-controls input[type='range'] {
|
193
|
+
-webkit-appearance: none;
|
194
|
+
height: 6px;
|
195
|
+
width: 100px;
|
196
|
+
margin-top: 8px;
|
197
|
+
background-color: #E6E6E6;
|
198
|
+
outline:none;
|
199
|
+
}
|
200
|
+
.px-video-controls input[type='range']:focus::-webkit-slider-thumb {
|
201
|
+
outline: 1px #999 dotted;
|
202
|
+
}
|
203
|
+
.px-video-controls input[type='range']::-moz-range-track {
|
204
|
+
-moz-appearance: none;
|
205
|
+
height: 6px;
|
206
|
+
background-color: #E6E6E6;
|
207
|
+
border: none;
|
208
|
+
}
|
209
|
+
.px-video-controls input[type='range']::-webkit-slider-thumb {
|
210
|
+
-webkit-appearance: none !important;
|
211
|
+
height: 10px;
|
212
|
+
width: 6px;
|
213
|
+
background-color: #666;
|
214
|
+
}
|
215
|
+
.px-video-controls input[type='range']::-moz-range-thumb {
|
216
|
+
height: 12px;
|
217
|
+
width: 8px;
|
218
|
+
}
|
219
|
+
/* fixing display for IE10+ */
|
220
|
+
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
221
|
+
.px-video-controls input[type='range'] {
|
222
|
+
position: relative;
|
223
|
+
padding: 0;
|
224
|
+
height: 8px;
|
225
|
+
top: -3px;
|
226
|
+
}
|
227
|
+
.px-video-time {
|
228
|
+
margin-top: 4px;
|
229
|
+
}
|
230
|
+
.px-video-captions {
|
231
|
+
padding: 8px;
|
232
|
+
min-height: 36px;
|
233
|
+
}
|
234
|
+
}
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pxvideo_rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexandr Kardakov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-15 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: '%q{HTML5 PxVideo plugin}'
|
14
|
+
email: razielsun@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- .gitignore
|
20
|
+
- Rakefile
|
21
|
+
- Readme.md
|
22
|
+
- app/views/pxvideo_rails/_pxvideo_rails.html.erb
|
23
|
+
- lib/pxvideo_rails.rb
|
24
|
+
- lib/pxvideo_rails/engine.rb
|
25
|
+
- lib/pxvideo_rails/railtie.rb
|
26
|
+
- lib/pxvideo_rails/view_helpers.rb
|
27
|
+
- pxvideo_rails.gemspec
|
28
|
+
- vendor/assets/LICENSE.md
|
29
|
+
- vendor/assets/images/px-video-sprite.png
|
30
|
+
- vendor/assets/javascripts/px-video.js
|
31
|
+
- vendor/assets/stylesheets/px-video.css.erb
|
32
|
+
homepage: ''
|
33
|
+
licenses: []
|
34
|
+
metadata: {}
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 2.4.1
|
52
|
+
signing_key:
|
53
|
+
specification_version: 4
|
54
|
+
summary: '%q{Pxvideo html5 video plugin}'
|
55
|
+
test_files: []
|