rails-audiojs 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/README.markdown +40 -0
- data/Rakefile +12 -0
- data/lib/audiojs/rails.rb +11 -0
- data/lib/audiojs/rails/version.rb +5 -0
- data/test/dummy/app/assets/javascripts/application.js +5 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +18 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +1 -0
- data/test/dummy/config/routes.rb +2 -0
- data/test/rails_audiojs_test.rb +35 -0
- data/test/test_helper.rb +7 -0
- data/vendor/assets/javascripts/audiojs-player-graphics.gif +0 -0
- data/vendor/assets/javascripts/audiojs.js.erb +729 -0
- data/vendor/assets/javascripts/audiojs.swf +0 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1a192554eecb54bbf0a8f21c193966fcd4f25e00
|
4
|
+
data.tar.gz: c407bbdc7a372172e535a5c8f67307f5ce73bf72
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bc3266040c6575ea5516af5114bd78f400418e1028a922472af1b4487d6fec5e65d172e0fa293f4fe5e1a8a80136c32db019faea209b5d318e2052dc7a2d29e6
|
7
|
+
data.tar.gz: 7a13c9e686a63ff51eec6e99f45d6765aa7d5d8ff72158053366c97a774d6a267bc8cb582e1875b7d43793f94b3fd85a36ab1ef047ac38dc525836c5469565da
|
data/README.markdown
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Audiojs
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/audiojs-rails.png)](http://badge.fury.io/rb/audiojs-rails)
|
4
|
+
[![Build Status](https://secure.travis-ci.org/subosito/audiojs-rails.png)](http://travis-ci.org/subosito/audiojs-rails)
|
5
|
+
[![Dependency Status](https://gemnasium.com/subosito/audiojs-rails.png)](https://gemnasium.com/subosito/audiojs-rails)
|
6
|
+
|
7
|
+
![Logo](docs/images/audiojs.png)
|
8
|
+
|
9
|
+
[audio.js](http://kolber.github.com/audiojs/) is a drop-in javascript library that allows HTML5's <audio> tag to be used anywhere.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'audiojs-rails'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install audiojs-rails
|
24
|
+
|
25
|
+
Put on your `application.js`:
|
26
|
+
|
27
|
+
//= require audiojs
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create new Pull Request
|
36
|
+
|
37
|
+
## Credits
|
38
|
+
|
39
|
+
Thanks for [Anthony Kolber](https://github.com/kolber) for creating audio.js. You can read more about audio.js on http://kolber.github.com/audiojs/.
|
40
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
|
3
|
+
# require "rails/all"
|
4
|
+
require "sprockets/railtie"
|
5
|
+
|
6
|
+
Bundler.require(:default, :development)
|
7
|
+
|
8
|
+
module Dummy
|
9
|
+
class Application < Rails::Application
|
10
|
+
config.encoding = "utf-8"
|
11
|
+
config.assets.enabled = true
|
12
|
+
config.assets.version = '1.0'
|
13
|
+
|
14
|
+
# replacement for environments/*.rb
|
15
|
+
config.active_support.deprecation = :stderr
|
16
|
+
config.eager_load = false
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Dummy::Application.config.secret_token = "e7a25db6bb3c9b96ccdc16af17d4128ffa28152252b319f375ef16900efdcefb5890935a5df6d1362c350eee6eb75470daf42d2e340aa723b93702e14358d01a"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AudiojsRailsTest < ActionDispatch::IntegrationTest
|
4
|
+
teardown { clean_cache }
|
5
|
+
|
6
|
+
test "engine is loaded" do
|
7
|
+
assert_equal ::Rails::Engine, Audiojs::Rails::Engine.superclass
|
8
|
+
end
|
9
|
+
|
10
|
+
test "javascript is served" do
|
11
|
+
get "/assets/audiojs.js"
|
12
|
+
assert_response :success
|
13
|
+
end
|
14
|
+
|
15
|
+
test "image is served" do
|
16
|
+
get "/assets/audiojs-player-graphics.gif"
|
17
|
+
assert_response :success
|
18
|
+
end
|
19
|
+
|
20
|
+
test "flash is served" do
|
21
|
+
get "/assets/audiojs.swf"
|
22
|
+
assert_response :success
|
23
|
+
end
|
24
|
+
|
25
|
+
test "javascript contain references to graphics (image and flash)" do
|
26
|
+
get "/assets/audiojs.js"
|
27
|
+
assert_match "/assets/audiojs.swf", response.body
|
28
|
+
assert_match "/assets/audiojs-player-graphics.gif", response.body
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def clean_cache
|
33
|
+
FileUtils.rm_rf File.expand_path("../dummy/tmp", __FILE__)
|
34
|
+
end
|
35
|
+
end
|
data/test/test_helper.rb
ADDED
Binary file
|
@@ -0,0 +1,729 @@
|
|
1
|
+
// A cross-browser javascript shim for html5 audio
|
2
|
+
(function(audiojs, audiojsInstance, container) {
|
3
|
+
// Use the path to the audio.js file to create relative paths to the swf and player graphics
|
4
|
+
// Remember that some systems (e.g. ruby on rails) append strings like '?1301478336' to asset paths
|
5
|
+
var path = (function() {
|
6
|
+
var re = new RegExp('audio(\.min)?\.js.*'),
|
7
|
+
scripts = document.getElementsByTagName('script');
|
8
|
+
for (var i = 0, ii = scripts.length; i < ii; i++) {
|
9
|
+
var path = scripts[i].getAttribute('src');
|
10
|
+
if(re.test(path))
|
11
|
+
{
|
12
|
+
var f = path.split ( '/' );
|
13
|
+
f.pop ();
|
14
|
+
return f.join ( '/' ) + '/';
|
15
|
+
}
|
16
|
+
}
|
17
|
+
// when no script found, an empty string causes the least confusion.
|
18
|
+
return '';
|
19
|
+
})();
|
20
|
+
|
21
|
+
// ##The audiojs interface
|
22
|
+
// This is the global object which provides an interface for creating new `audiojs` instances.
|
23
|
+
// It also stores all of the construction helper methods and variables.
|
24
|
+
container[audiojs] = {
|
25
|
+
instanceCount: 0,
|
26
|
+
instances: {},
|
27
|
+
// The markup for the swf. It is injected into the page if there is not support for the `<audio>` element. The `$n`s are placeholders.
|
28
|
+
// `$1` The name of the flash movie
|
29
|
+
// `$2` The path to the swf
|
30
|
+
// `$3` Cache invalidation
|
31
|
+
flashSource: '\
|
32
|
+
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="$1" width="1" height="1" name="$1" style="position: absolute; left: -1px;"> \
|
33
|
+
<param name="movie" value="$2?playerInstance='+audiojs+'.instances[\'$1\']&datetime=$3"> \
|
34
|
+
<param name="allowscriptaccess" value="always"> \
|
35
|
+
<embed name="$1" src="$2?playerInstance='+audiojs+'.instances[\'$1\']&datetime=$3" width="1" height="1" allowscriptaccess="always"> \
|
36
|
+
</object>',
|
37
|
+
|
38
|
+
// ### The main settings object
|
39
|
+
// Where all the default settings are stored. Each of these variables and methods can be overwritten by the user-provided `options` object.
|
40
|
+
settings: {
|
41
|
+
autoplay: false,
|
42
|
+
loop: false,
|
43
|
+
preload: true,
|
44
|
+
imageLocation: path + 'player-graphics.gif',
|
45
|
+
retinaImageLocation: path + 'player-graphics@2x.gif',
|
46
|
+
swfLocation: path + 'audiojs.swf',
|
47
|
+
useFlash: (function() {
|
48
|
+
var a = document.createElement('audio');
|
49
|
+
return !(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
|
50
|
+
})(),
|
51
|
+
hasFlash: (function() {
|
52
|
+
if (navigator.plugins && navigator.plugins.length && navigator.plugins['Shockwave Flash']) {
|
53
|
+
return true;
|
54
|
+
} else if (navigator.mimeTypes && navigator.mimeTypes.length) {
|
55
|
+
var mimeType = navigator.mimeTypes['application/x-shockwave-flash'];
|
56
|
+
return mimeType && mimeType.enabledPlugin;
|
57
|
+
} else {
|
58
|
+
try {
|
59
|
+
var ax = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
|
60
|
+
return true;
|
61
|
+
} catch (e) {}
|
62
|
+
}
|
63
|
+
return false;
|
64
|
+
})(),
|
65
|
+
// The default markup and classes for creating the player:
|
66
|
+
createPlayer: {
|
67
|
+
markup: '\
|
68
|
+
<div class="play-pause"> \
|
69
|
+
<p class="play"></p> \
|
70
|
+
<p class="pause"></p> \
|
71
|
+
<p class="loading"></p> \
|
72
|
+
<p class="error"></p> \
|
73
|
+
</div> \
|
74
|
+
<div class="scrubber"> \
|
75
|
+
<div class="progress"></div> \
|
76
|
+
<div class="loaded"></div> \
|
77
|
+
</div> \
|
78
|
+
<div class="time"> \
|
79
|
+
<em class="played">00:00</em>/<strong class="duration">00:00</strong> \
|
80
|
+
</div> \
|
81
|
+
<div class="error-message"></div>',
|
82
|
+
playPauseClass: 'play-pause',
|
83
|
+
scrubberClass: 'scrubber',
|
84
|
+
progressClass: 'progress',
|
85
|
+
loaderClass: 'loaded',
|
86
|
+
timeClass: 'time',
|
87
|
+
durationClass: 'duration',
|
88
|
+
playedClass: 'played',
|
89
|
+
errorMessageClass: 'error-message',
|
90
|
+
playingClass: 'playing',
|
91
|
+
loadingClass: 'loading',
|
92
|
+
errorClass: 'error'
|
93
|
+
},
|
94
|
+
// The css used by the default player. This is is dynamically injected into a `<style>` tag in the top of the head.
|
95
|
+
css: '\
|
96
|
+
.audiojs audio { position: absolute; left: -1px; } \
|
97
|
+
.audiojs { width: 460px; height: 36px; background: #404040; overflow: hidden; font-family: monospace; font-size: 12px; \
|
98
|
+
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #444), color-stop(0.5, #555), color-stop(0.51, #444), color-stop(1, #444)); \
|
99
|
+
background-image: -moz-linear-gradient(center top, #444 0%, #555 50%, #444 51%, #444 100%); \
|
100
|
+
-webkit-box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.3); -moz-box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.3); \
|
101
|
+
-o-box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.3); box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.3); } \
|
102
|
+
.audiojs .play-pause { width: 25px; height: 40px; padding: 4px 6px; margin: 0px; float: left; overflow: hidden; border-right: 1px solid #000; } \
|
103
|
+
.audiojs p { display: none; width: 25px; height: 40px; margin: 0px; cursor: pointer; } \
|
104
|
+
.audiojs .play { display: block; } \
|
105
|
+
.audiojs .scrubber { position: relative; float: left; width: 280px; background: #5a5a5a; height: 14px; margin: 10px; border-top: 1px solid #3f3f3f; border-left: 0px; border-bottom: 0px; overflow: hidden; } \
|
106
|
+
.audiojs .progress { position: absolute; top: 0px; left: 0px; height: 14px; width: 0px; background: #ccc; z-index: 1; \
|
107
|
+
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #ccc), color-stop(0.5, #ddd), color-stop(0.51, #ccc), color-stop(1, #ccc)); \
|
108
|
+
background-image: -moz-linear-gradient(center top, #ccc 0%, #ddd 50%, #ccc 51%, #ccc 100%); } \
|
109
|
+
.audiojs .loaded { position: absolute; top: 0px; left: 0px; height: 14px; width: 0px; background: #000; \
|
110
|
+
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #222), color-stop(0.5, #333), color-stop(0.51, #222), color-stop(1, #222)); \
|
111
|
+
background-image: -moz-linear-gradient(center top, #222 0%, #333 50%, #222 51%, #222 100%); } \
|
112
|
+
.audiojs .time { float: left; height: 36px; line-height: 36px; margin: 0px 0px 0px 6px; padding: 0px 6px 0px 12px; border-left: 1px solid #000; color: #ddd; text-shadow: 1px 1px 0px rgba(0, 0, 0, 0.5); } \
|
113
|
+
.audiojs .time em { padding: 0px 2px 0px 0px; color: #f9f9f9; font-style: normal; } \
|
114
|
+
.audiojs .time strong { padding: 0px 0px 0px 2px; font-weight: normal; } \
|
115
|
+
.audiojs .error-message { float: left; display: none; margin: 0px 10px; height: 36px; width: 400px; overflow: hidden; line-height: 36px; white-space: nowrap; color: #fff; \
|
116
|
+
text-overflow: ellipsis; -o-text-overflow: ellipsis; -icab-text-overflow: ellipsis; -khtml-text-overflow: ellipsis; -moz-text-overflow: ellipsis; -webkit-text-overflow: ellipsis; } \
|
117
|
+
.audiojs .error-message a { color: #eee; text-decoration: none; padding-bottom: 1px; border-bottom: 1px solid #999; white-space: wrap; } \
|
118
|
+
\
|
119
|
+
.audiojs .play { background: url("$1") -2px -1px no-repeat; } \
|
120
|
+
.audiojs .loading { background: url("$1") -2px -31px no-repeat; } \
|
121
|
+
.audiojs .error { background: url("$1") -2px -61px no-repeat; } \
|
122
|
+
.audiojs .pause { background: url("$1") -2px -91px no-repeat; } \
|
123
|
+
\
|
124
|
+
@media only screen and (-webkit-min-device-pixel-ratio: 2), \
|
125
|
+
only screen and (min--moz-device-pixel-ratio: 2), \
|
126
|
+
only screen and (min-moz-device-pixel-ratio: 2), \
|
127
|
+
only screen and (-o-min-device-pixel-ratio: 2/1), \
|
128
|
+
only screen and (min-device-pixel-ratio: 2) { \
|
129
|
+
.audiojs .play, .audiojs .loading, .audiojs .error, .audiojs .pause { \
|
130
|
+
background-image: url("$2"); \
|
131
|
+
-webkit-background-size: 30px 120px; \
|
132
|
+
-moz-background-size: 30px 120px; \
|
133
|
+
-o-background-size: 30px 120px; \
|
134
|
+
background-size: 30px 120px; \
|
135
|
+
} \
|
136
|
+
} \
|
137
|
+
\
|
138
|
+
.playing .play, .playing .loading, .playing .error { display: none; } \
|
139
|
+
.playing .pause { display: block; } \
|
140
|
+
\
|
141
|
+
.loading .play, .loading .pause, .loading .error { display: none; } \
|
142
|
+
.loading .loading { display: block; } \
|
143
|
+
\
|
144
|
+
.error .time, .error .play, .error .pause, .error .scrubber, .error .loading { display: none; } \
|
145
|
+
.error .error { display: block; } \
|
146
|
+
.error .play-pause p { cursor: auto; } \
|
147
|
+
.error .error-message { display: block; }',
|
148
|
+
// The default event callbacks:
|
149
|
+
trackEnded: function(e) {},
|
150
|
+
flashError: function() {
|
151
|
+
var player = this.settings.createPlayer,
|
152
|
+
errorMessage = getByClass(player.errorMessageClass, this.wrapper),
|
153
|
+
html = 'Missing <a href="http://get.adobe.com/flashplayer/">flash player</a> plugin.';
|
154
|
+
if (this.mp3) html += ' <a href="'+this.mp3+'">Download audio file</a>.';
|
155
|
+
container[audiojs].helpers.removeClass(this.wrapper, player.loadingClass);
|
156
|
+
container[audiojs].helpers.addClass(this.wrapper, player.errorClass);
|
157
|
+
errorMessage.innerHTML = html;
|
158
|
+
},
|
159
|
+
loadError: function(e) {
|
160
|
+
var player = this.settings.createPlayer,
|
161
|
+
errorMessage = getByClass(player.errorMessageClass, this.wrapper);
|
162
|
+
container[audiojs].helpers.removeClass(this.wrapper, player.loadingClass);
|
163
|
+
container[audiojs].helpers.addClass(this.wrapper, player.errorClass);
|
164
|
+
errorMessage.innerHTML = 'Error loading: "'+this.mp3+'"';
|
165
|
+
},
|
166
|
+
init: function() {
|
167
|
+
var player = this.settings.createPlayer;
|
168
|
+
container[audiojs].helpers.addClass(this.wrapper, player.loadingClass);
|
169
|
+
},
|
170
|
+
loadStarted: function() {
|
171
|
+
var player = this.settings.createPlayer,
|
172
|
+
duration = getByClass(player.durationClass, this.wrapper),
|
173
|
+
m = Math.floor(this.duration / 60),
|
174
|
+
s = Math.floor(this.duration % 60);
|
175
|
+
container[audiojs].helpers.removeClass(this.wrapper, player.loadingClass);
|
176
|
+
duration.innerHTML = ((m<10?'0':'')+m+':'+(s<10?'0':'')+s);
|
177
|
+
},
|
178
|
+
loadProgress: function(percent) {
|
179
|
+
var player = this.settings.createPlayer,
|
180
|
+
loaded = getByClass(player.loaderClass, this.wrapper);
|
181
|
+
loaded.style.width = Math.round(100 * percent) + '%';
|
182
|
+
},
|
183
|
+
playPause: function() {
|
184
|
+
if (this.playing) this.settings.play();
|
185
|
+
else this.settings.pause();
|
186
|
+
},
|
187
|
+
play: function() {
|
188
|
+
var player = this.settings.createPlayer;
|
189
|
+
container[audiojs].helpers.removeClass(this.wrapper, player.errorClass);
|
190
|
+
container[audiojs].helpers.addClass(this.wrapper, player.playingClass);
|
191
|
+
},
|
192
|
+
pause: function() {
|
193
|
+
var player = this.settings.createPlayer;
|
194
|
+
container[audiojs].helpers.removeClass(this.wrapper, player.playingClass);
|
195
|
+
},
|
196
|
+
updatePlayhead: function(percent) {
|
197
|
+
var player = this.settings.createPlayer,
|
198
|
+
progress = getByClass(player.progressClass, this.wrapper);
|
199
|
+
progress.style.width = Math.round(100 * percent) + '%';
|
200
|
+
|
201
|
+
var played = getByClass(player.playedClass, this.wrapper),
|
202
|
+
p = this.duration * percent,
|
203
|
+
m = Math.floor(p / 60),
|
204
|
+
s = Math.floor(p % 60);
|
205
|
+
played.innerHTML = ((m<10?'0':'')+m+':'+(s<10?'0':'')+s);
|
206
|
+
}
|
207
|
+
},
|
208
|
+
|
209
|
+
// ### Contructor functions
|
210
|
+
|
211
|
+
// `create()`
|
212
|
+
// Used to create a single `audiojs` instance.
|
213
|
+
// If an array is passed then it calls back to `createAll()`.
|
214
|
+
// Otherwise, it creates a single instance and returns it.
|
215
|
+
create: function(element, options) {
|
216
|
+
var options = options || {}
|
217
|
+
if (element.length) {
|
218
|
+
return this.createAll(options, element);
|
219
|
+
} else {
|
220
|
+
return this.newInstance(element, options);
|
221
|
+
}
|
222
|
+
},
|
223
|
+
|
224
|
+
// `createAll()`
|
225
|
+
// Creates multiple `audiojs` instances.
|
226
|
+
// If `elements` is `null`, then automatically find any `<audio>` tags on the page and create `audiojs` instances for them.
|
227
|
+
createAll: function(options, elements) {
|
228
|
+
var audioElements = elements || document.getElementsByTagName('audio'),
|
229
|
+
instances = []
|
230
|
+
options = options || {};
|
231
|
+
for (var i = 0, ii = audioElements.length; i < ii; i++) {
|
232
|
+
|
233
|
+
if ((" " + audioElements[i].parentNode.className + " ").replace(/[\n\t]/g, " ").indexOf(" audiojs ") > -1)
|
234
|
+
continue;
|
235
|
+
|
236
|
+
instances.push(this.newInstance(audioElements[i], options));
|
237
|
+
}
|
238
|
+
return instances;
|
239
|
+
},
|
240
|
+
|
241
|
+
// ### Creating and returning a new instance
|
242
|
+
// This goes through all the steps required to build out a usable `audiojs` instance.
|
243
|
+
newInstance: function(element, options) {
|
244
|
+
var element = element,
|
245
|
+
s = this.helpers.clone(this.settings),
|
246
|
+
id = 'audiojs'+this.instanceCount,
|
247
|
+
wrapperId = 'audiojs_wrapper'+this.instanceCount,
|
248
|
+
instanceCount = this.instanceCount++;
|
249
|
+
|
250
|
+
// Check for `autoplay`, `loop` and `preload` attributes and write them into the settings.
|
251
|
+
if (element.getAttribute('autoplay') != null) s.autoplay = true;
|
252
|
+
if (element.getAttribute('loop') != null) s.loop = true;
|
253
|
+
if (element.getAttribute('preload') == 'none') s.preload = false;
|
254
|
+
// Merge the default settings with the user-defined `options`.
|
255
|
+
if (options) this.helpers.merge(s, options);
|
256
|
+
|
257
|
+
// Inject the player html if required.
|
258
|
+
if (s.createPlayer.markup) element = this.createPlayer(element, s.createPlayer, wrapperId);
|
259
|
+
else element.parentNode.setAttribute('id', wrapperId);
|
260
|
+
|
261
|
+
// Return a new `audiojs` instance.
|
262
|
+
var audio = new container[audiojsInstance](element, s);
|
263
|
+
|
264
|
+
// If css has been passed in, dynamically inject it into the `<head>`.
|
265
|
+
if (s.css) this.helpers.injectCss(audio, s.css);
|
266
|
+
|
267
|
+
// If `<audio>` or mp3 playback isn't supported, insert the swf & attach the required events for it.
|
268
|
+
if (s.useFlash && s.hasFlash) {
|
269
|
+
this.injectFlash(audio, id);
|
270
|
+
this.attachFlashEvents(audio.wrapper, audio);
|
271
|
+
} else if (s.useFlash && !s.hasFlash) {
|
272
|
+
s.flashError.apply(audio);
|
273
|
+
}
|
274
|
+
|
275
|
+
// Attach event callbacks to the new audiojs instance.
|
276
|
+
if (!s.useFlash || (s.useFlash && s.hasFlash)) this.attachEvents(audio.wrapper, audio);
|
277
|
+
|
278
|
+
// Store the newly-created `audiojs` instance.
|
279
|
+
this.instances[id] = audio;
|
280
|
+
return audio;
|
281
|
+
},
|
282
|
+
|
283
|
+
// ### Helper methods for constructing a working player
|
284
|
+
// Inject a wrapping div and the markup for the html player.
|
285
|
+
createPlayer: function(element, player, id) {
|
286
|
+
var wrapper = document.createElement('div'),
|
287
|
+
newElement = element.cloneNode(true);
|
288
|
+
wrapper.setAttribute('class', 'audiojs');
|
289
|
+
wrapper.setAttribute('className', 'audiojs');
|
290
|
+
wrapper.setAttribute('id', id);
|
291
|
+
|
292
|
+
// Fix IE's broken implementation of `innerHTML` & `cloneNode` for HTML5 elements.
|
293
|
+
if (newElement.outerHTML && !document.createElement('audio').canPlayType) {
|
294
|
+
newElement = this.helpers.cloneHtml5Node(element);
|
295
|
+
wrapper.innerHTML = player.markup;
|
296
|
+
wrapper.appendChild(newElement);
|
297
|
+
element.outerHTML = wrapper.outerHTML;
|
298
|
+
wrapper = document.getElementById(id);
|
299
|
+
} else {
|
300
|
+
wrapper.appendChild(newElement);
|
301
|
+
wrapper.innerHTML = wrapper.innerHTML + player.markup;
|
302
|
+
element.parentNode.replaceChild(wrapper, element);
|
303
|
+
}
|
304
|
+
return wrapper.getElementsByTagName('audio')[0];
|
305
|
+
},
|
306
|
+
|
307
|
+
// Attaches useful event callbacks to an `audiojs` instance.
|
308
|
+
attachEvents: function(wrapper, audio) {
|
309
|
+
if (!audio.settings.createPlayer) return;
|
310
|
+
var player = audio.settings.createPlayer,
|
311
|
+
playPause = getByClass(player.playPauseClass, wrapper),
|
312
|
+
scrubber = getByClass(player.scrubberClass, wrapper),
|
313
|
+
leftPos = function(elem) {
|
314
|
+
var curleft = 0;
|
315
|
+
if (elem.offsetParent) {
|
316
|
+
do { curleft += elem.offsetLeft; } while (elem = elem.offsetParent);
|
317
|
+
}
|
318
|
+
return curleft;
|
319
|
+
};
|
320
|
+
|
321
|
+
container[audiojs].events.addListener(playPause, 'click', function(e) {
|
322
|
+
audio.playPause.apply(audio);
|
323
|
+
});
|
324
|
+
|
325
|
+
container[audiojs].events.addListener(scrubber, 'click', function(e) {
|
326
|
+
var relativeLeft = e.clientX - leftPos(this);
|
327
|
+
audio.skipTo(relativeLeft / scrubber.offsetWidth);
|
328
|
+
});
|
329
|
+
|
330
|
+
// _If flash is being used, then the following handlers don't need to be registered._
|
331
|
+
if (audio.settings.useFlash) return;
|
332
|
+
|
333
|
+
// Start tracking the load progress of the track.
|
334
|
+
container[audiojs].events.trackLoadProgress(audio);
|
335
|
+
|
336
|
+
container[audiojs].events.addListener(audio.element, 'timeupdate', function(e) {
|
337
|
+
audio.updatePlayhead.apply(audio);
|
338
|
+
});
|
339
|
+
|
340
|
+
container[audiojs].events.addListener(audio.element, 'ended', function(e) {
|
341
|
+
audio.trackEnded.apply(audio);
|
342
|
+
});
|
343
|
+
|
344
|
+
container[audiojs].events.addListener(audio.source, 'error', function(e) {
|
345
|
+
// on error, cancel any load timers that are running.
|
346
|
+
clearInterval(audio.readyTimer);
|
347
|
+
clearInterval(audio.loadTimer);
|
348
|
+
audio.settings.loadError.apply(audio);
|
349
|
+
});
|
350
|
+
|
351
|
+
},
|
352
|
+
|
353
|
+
// Flash requires a slightly different API to the `<audio>` element, so this method is used to overwrite the standard event handlers.
|
354
|
+
attachFlashEvents: function(element, audio) {
|
355
|
+
audio['swfReady'] = false;
|
356
|
+
audio['load'] = function(mp3) {
|
357
|
+
// If the swf isn't ready yet then just set `audio.mp3`. `init()` will load it in once the swf is ready.
|
358
|
+
audio.mp3 = mp3;
|
359
|
+
if (audio.swfReady) audio.element.load(mp3);
|
360
|
+
}
|
361
|
+
audio['loadProgress'] = function(percent, duration) {
|
362
|
+
audio.loadedPercent = percent;
|
363
|
+
audio.duration = duration;
|
364
|
+
audio.settings.loadStarted.apply(audio);
|
365
|
+
audio.settings.loadProgress.apply(audio, [percent]);
|
366
|
+
}
|
367
|
+
audio['skipTo'] = function(percent) {
|
368
|
+
if (percent > audio.loadedPercent) return;
|
369
|
+
audio.updatePlayhead.call(audio, [percent])
|
370
|
+
audio.element.skipTo(percent);
|
371
|
+
}
|
372
|
+
audio['updatePlayhead'] = function(percent) {
|
373
|
+
audio.settings.updatePlayhead.apply(audio, [percent]);
|
374
|
+
}
|
375
|
+
audio['play'] = function() {
|
376
|
+
// If the audio hasn't started preloading, then start it now.
|
377
|
+
// Then set `preload` to `true`, so that any tracks loaded in subsequently are loaded straight away.
|
378
|
+
if (!audio.settings.preload) {
|
379
|
+
audio.settings.preload = true;
|
380
|
+
audio.element.init(audio.mp3);
|
381
|
+
}
|
382
|
+
audio.playing = true;
|
383
|
+
// IE doesn't allow a method named `play()` to be exposed through `ExternalInterface`, so lets go with `pplay()`.
|
384
|
+
// <http://dev.nuclearrooster.com/2008/07/27/externalinterfaceaddcallback-can-cause-ie-js-errors-with-certain-keyworkds/>
|
385
|
+
audio.element.pplay();
|
386
|
+
audio.settings.play.apply(audio);
|
387
|
+
}
|
388
|
+
audio['pause'] = function() {
|
389
|
+
audio.playing = false;
|
390
|
+
// Use `ppause()` for consistency with `pplay()`, even though it isn't really required.
|
391
|
+
audio.element.ppause();
|
392
|
+
audio.settings.pause.apply(audio);
|
393
|
+
}
|
394
|
+
audio['setVolume'] = function(v) {
|
395
|
+
audio.element.setVolume(v);
|
396
|
+
}
|
397
|
+
audio['loadStarted'] = function() {
|
398
|
+
// Load the mp3 specified by the audio element into the swf.
|
399
|
+
audio.swfReady = true;
|
400
|
+
if (audio.settings.preload) audio.element.init(audio.mp3);
|
401
|
+
if (audio.settings.autoplay) audio.play.apply(audio);
|
402
|
+
}
|
403
|
+
},
|
404
|
+
|
405
|
+
// ### Injecting an swf from a string
|
406
|
+
// Build up the swf source by replacing the `$keys` and then inject the markup into the page.
|
407
|
+
injectFlash: function(audio, id) {
|
408
|
+
var flashSource = this.flashSource.replace(/\$1/g, id);
|
409
|
+
flashSource = flashSource.replace(/\$2/g, audio.settings.swfLocation);
|
410
|
+
// `(+new Date)` ensures the swf is not pulled out of cache. The fixes an issue with Firefox running multiple players on the same page.
|
411
|
+
flashSource = flashSource.replace(/\$3/g, (+new Date + Math.random()));
|
412
|
+
// Inject the player markup using a more verbose `innerHTML` insertion technique that works with IE.
|
413
|
+
var html = audio.wrapper.innerHTML,
|
414
|
+
div = document.createElement('div');
|
415
|
+
div.innerHTML = flashSource + html;
|
416
|
+
audio.wrapper.innerHTML = div.innerHTML;
|
417
|
+
audio.element = this.helpers.getSwf(id);
|
418
|
+
},
|
419
|
+
|
420
|
+
// ## Helper functions
|
421
|
+
helpers: {
|
422
|
+
// **Merge two objects, with `obj2` overwriting `obj1`**
|
423
|
+
// The merge is shallow, but that's all that is required for our purposes.
|
424
|
+
merge: function(obj1, obj2) {
|
425
|
+
for (attr in obj2) {
|
426
|
+
if (obj1.hasOwnProperty(attr) || obj2.hasOwnProperty(attr)) {
|
427
|
+
obj1[attr] = obj2[attr];
|
428
|
+
}
|
429
|
+
}
|
430
|
+
},
|
431
|
+
// **Clone a javascript object (recursively)**
|
432
|
+
clone: function(obj){
|
433
|
+
if (obj == null || typeof(obj) !== 'object') return obj;
|
434
|
+
var temp = new obj.constructor();
|
435
|
+
for (var key in obj) temp[key] = arguments.callee(obj[key]);
|
436
|
+
return temp;
|
437
|
+
},
|
438
|
+
// **Adding/removing classnames from elements**
|
439
|
+
addClass: function(element, className) {
|
440
|
+
var re = new RegExp('(\\s|^)'+className+'(\\s|$)');
|
441
|
+
if (re.test(element.className)) return;
|
442
|
+
element.className += ' ' + className;
|
443
|
+
},
|
444
|
+
removeClass: function(element, className) {
|
445
|
+
var re = new RegExp('(\\s|^)'+className+'(\\s|$)');
|
446
|
+
element.className = element.className.replace(re,' ');
|
447
|
+
},
|
448
|
+
// **Dynamic CSS injection**
|
449
|
+
// Takes a string of css, inserts it into a `<style>`, then injects it in at the very top of the `<head>`. This ensures any user-defined styles will take precedence.
|
450
|
+
injectCss: function(audio, string) {
|
451
|
+
|
452
|
+
// If an `audiojs` `<style>` tag already exists, then append to it rather than creating a whole new `<style>`.
|
453
|
+
var prepend = '',
|
454
|
+
styles = document.getElementsByTagName('style'),
|
455
|
+
css = string.replace(/\$1/g, audio.settings.imageLocation);
|
456
|
+
css = css.replace(/\$2/g, audio.settings.retinaImageLocation);
|
457
|
+
|
458
|
+
for (var i = 0, ii = styles.length; i < ii; i++) {
|
459
|
+
var title = styles[i].getAttribute('title');
|
460
|
+
if (title && ~title.indexOf('audiojs')) {
|
461
|
+
style = styles[i];
|
462
|
+
if (style.innerHTML === css) return;
|
463
|
+
prepend = style.innerHTML;
|
464
|
+
break;
|
465
|
+
}
|
466
|
+
};
|
467
|
+
|
468
|
+
var head = document.getElementsByTagName('head')[0],
|
469
|
+
firstchild = head.firstChild,
|
470
|
+
style = document.createElement('style');
|
471
|
+
|
472
|
+
if (!head) return;
|
473
|
+
|
474
|
+
style.setAttribute('type', 'text/css');
|
475
|
+
style.setAttribute('title', 'audiojs');
|
476
|
+
|
477
|
+
if (style.styleSheet) style.styleSheet.cssText = prepend + css;
|
478
|
+
else style.appendChild(document.createTextNode(prepend + css));
|
479
|
+
|
480
|
+
if (firstchild) head.insertBefore(style, firstchild);
|
481
|
+
else head.appendChild(style);
|
482
|
+
},
|
483
|
+
// **Handle all the IE6+7 requirements for cloning `<audio>` nodes**
|
484
|
+
// Create a html5-safe document fragment by injecting an `<audio>` element into the document fragment.
|
485
|
+
cloneHtml5Node: function(audioTag) {
|
486
|
+
var fragment = document.createDocumentFragment(),
|
487
|
+
doc = fragment.createElement ? fragment : document;
|
488
|
+
doc.createElement('audio');
|
489
|
+
var div = doc.createElement('div');
|
490
|
+
fragment.appendChild(div);
|
491
|
+
div.innerHTML = audioTag.outerHTML;
|
492
|
+
return div.firstChild;
|
493
|
+
},
|
494
|
+
// **Cross-browser `<object>` / `<embed>` element selection**
|
495
|
+
getSwf: function(name) {
|
496
|
+
var swf = document[name] || window[name];
|
497
|
+
return swf.length > 1 ? swf[swf.length - 1] : swf;
|
498
|
+
}
|
499
|
+
},
|
500
|
+
// ## Event-handling
|
501
|
+
events: {
|
502
|
+
memoryLeaking: false,
|
503
|
+
listeners: [],
|
504
|
+
// **A simple cross-browser event handler abstraction**
|
505
|
+
addListener: function(element, eventName, func) {
|
506
|
+
// For modern browsers use the standard DOM-compliant `addEventListener`.
|
507
|
+
if (element.addEventListener) {
|
508
|
+
element.addEventListener(eventName, func, false);
|
509
|
+
// For older versions of Internet Explorer, use `attachEvent`.
|
510
|
+
// Also provide a fix for scoping `this` to the calling element and register each listener so the containing elements can be purged on page unload.
|
511
|
+
} else if (element.attachEvent) {
|
512
|
+
this.listeners.push(element);
|
513
|
+
if (!this.memoryLeaking) {
|
514
|
+
window.attachEvent('onunload', function() {
|
515
|
+
if(this.listeners) {
|
516
|
+
for (var i = 0, ii = this.listeners.length; i < ii; i++) {
|
517
|
+
container[audiojs].events.purge(this.listeners[i]);
|
518
|
+
}
|
519
|
+
}
|
520
|
+
});
|
521
|
+
this.memoryLeaking = true;
|
522
|
+
}
|
523
|
+
element.attachEvent('on' + eventName, function() {
|
524
|
+
func.call(element, window.event);
|
525
|
+
});
|
526
|
+
}
|
527
|
+
},
|
528
|
+
|
529
|
+
trackLoadProgress: function(audio) {
|
530
|
+
// If `preload` has been set to `none`, then we don't want to start loading the track yet.
|
531
|
+
if (!audio.settings.preload) return;
|
532
|
+
|
533
|
+
var readyTimer,
|
534
|
+
loadTimer,
|
535
|
+
audio = audio,
|
536
|
+
ios = (/(ipod|iphone|ipad)/i).test(navigator.userAgent);
|
537
|
+
|
538
|
+
// Use timers here rather than the official `progress` event, as Chrome has issues calling `progress` when loading mp3 files from cache.
|
539
|
+
readyTimer = setInterval(function() {
|
540
|
+
if (audio.element.readyState > -1) {
|
541
|
+
// iOS doesn't start preloading the mp3 until the user interacts manually, so this stops the loader being displayed prematurely.
|
542
|
+
if (!ios) audio.init.apply(audio);
|
543
|
+
}
|
544
|
+
if (audio.element.readyState > 1) {
|
545
|
+
if (audio.settings.autoplay) audio.play.apply(audio);
|
546
|
+
clearInterval(readyTimer);
|
547
|
+
// Once we have data, start tracking the load progress.
|
548
|
+
loadTimer = setInterval(function() {
|
549
|
+
audio.loadProgress.apply(audio);
|
550
|
+
if (audio.loadedPercent >= 1) clearInterval(loadTimer);
|
551
|
+
}, 200);
|
552
|
+
}
|
553
|
+
}, 200);
|
554
|
+
audio.readyTimer = readyTimer;
|
555
|
+
audio.loadTimer = loadTimer;
|
556
|
+
},
|
557
|
+
|
558
|
+
// **Douglas Crockford's IE6 memory leak fix**
|
559
|
+
// <http://javascript.crockford.com/memory/leak.html>
|
560
|
+
// This is used to release the memory leak created by the circular references created when fixing `this` scoping for IE. It is called on page unload.
|
561
|
+
purge: function(d) {
|
562
|
+
var a = d.attributes, i;
|
563
|
+
if (a) {
|
564
|
+
for (i = 0; i < a.length; i += 1) {
|
565
|
+
if (typeof d[a[i].name] === 'function') d[a[i].name] = null;
|
566
|
+
}
|
567
|
+
}
|
568
|
+
a = d.childNodes;
|
569
|
+
if (a) {
|
570
|
+
for (i = 0; i < a.length; i += 1) purge(d.childNodes[i]);
|
571
|
+
}
|
572
|
+
},
|
573
|
+
|
574
|
+
// **DOMready function**
|
575
|
+
// As seen here: <https://github.com/dperini/ContentLoaded/>.
|
576
|
+
ready: (function() { return function(fn) {
|
577
|
+
var win = window, done = false, top = true,
|
578
|
+
doc = win.document, root = doc.documentElement,
|
579
|
+
add = doc.addEventListener ? 'addEventListener' : 'attachEvent',
|
580
|
+
rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',
|
581
|
+
pre = doc.addEventListener ? '' : 'on',
|
582
|
+
init = function(e) {
|
583
|
+
if (e.type == 'readystatechange' && doc.readyState != 'complete') return;
|
584
|
+
(e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
|
585
|
+
if (!done && (done = true)) fn.call(win, e.type || e);
|
586
|
+
},
|
587
|
+
poll = function() {
|
588
|
+
try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
|
589
|
+
init('poll');
|
590
|
+
};
|
591
|
+
if (doc.readyState == 'complete') fn.call(win, 'lazy');
|
592
|
+
else {
|
593
|
+
if (doc.createEventObject && root.doScroll) {
|
594
|
+
try { top = !win.frameElement; } catch(e) { }
|
595
|
+
if (top) poll();
|
596
|
+
}
|
597
|
+
doc[add](pre + 'DOMContentLoaded', init, false);
|
598
|
+
doc[add](pre + 'readystatechange', init, false);
|
599
|
+
win[add](pre + 'load', init, false);
|
600
|
+
}
|
601
|
+
}
|
602
|
+
})()
|
603
|
+
|
604
|
+
}
|
605
|
+
}
|
606
|
+
|
607
|
+
// ## The audiojs class
|
608
|
+
// We create one of these per `<audio>` and then push them into `audiojs['instances']`.
|
609
|
+
container[audiojsInstance] = function(element, settings) {
|
610
|
+
// Each audio instance returns an object which contains an API back into the `<audio>` element.
|
611
|
+
this.element = element;
|
612
|
+
this.wrapper = element.parentNode;
|
613
|
+
this.source = element.getElementsByTagName('source')[0] || element;
|
614
|
+
// First check the `<audio>` element directly for a src and if one is not found, look for a `<source>` element.
|
615
|
+
this.mp3 = (function(element) {
|
616
|
+
var source = element.getElementsByTagName('source')[0];
|
617
|
+
return element.getAttribute('src') || (source ? source.getAttribute('src') : null);
|
618
|
+
})(element);
|
619
|
+
this.settings = settings;
|
620
|
+
this.loadStartedCalled = false;
|
621
|
+
this.loadedPercent = 0;
|
622
|
+
this.duration = 1;
|
623
|
+
this.playing = false;
|
624
|
+
}
|
625
|
+
|
626
|
+
container[audiojsInstance].prototype = {
|
627
|
+
// API access events:
|
628
|
+
// Each of these do what they need do and then call the matching methods defined in the settings object.
|
629
|
+
updatePlayhead: function() {
|
630
|
+
var percent = this.element.currentTime / this.duration;
|
631
|
+
this.settings.updatePlayhead.apply(this, [percent]);
|
632
|
+
},
|
633
|
+
skipTo: function(percent) {
|
634
|
+
if (percent > this.loadedPercent) return;
|
635
|
+
this.element.currentTime = this.duration * percent;
|
636
|
+
this.updatePlayhead();
|
637
|
+
},
|
638
|
+
load: function(mp3) {
|
639
|
+
this.loadStartedCalled = false;
|
640
|
+
this.source.setAttribute('src', mp3);
|
641
|
+
// The now outdated `load()` method is required for Safari 4
|
642
|
+
this.element.load();
|
643
|
+
this.mp3 = mp3;
|
644
|
+
container[audiojs].events.trackLoadProgress(this);
|
645
|
+
},
|
646
|
+
loadError: function() {
|
647
|
+
this.settings.loadError.apply(this);
|
648
|
+
},
|
649
|
+
init: function() {
|
650
|
+
this.settings.init.apply(this);
|
651
|
+
},
|
652
|
+
loadStarted: function() {
|
653
|
+
// Wait until `element.duration` exists before setting up the audio player.
|
654
|
+
if (!this.element.duration) return false;
|
655
|
+
|
656
|
+
this.duration = this.element.duration;
|
657
|
+
this.updatePlayhead();
|
658
|
+
this.settings.loadStarted.apply(this);
|
659
|
+
},
|
660
|
+
loadProgress: function() {
|
661
|
+
if (this.element.buffered != null && this.element.buffered.length) {
|
662
|
+
// Ensure `loadStarted()` is only called once.
|
663
|
+
if (!this.loadStartedCalled) {
|
664
|
+
this.loadStartedCalled = this.loadStarted();
|
665
|
+
}
|
666
|
+
var durationLoaded = this.element.buffered.end(this.element.buffered.length - 1);
|
667
|
+
this.loadedPercent = durationLoaded / this.duration;
|
668
|
+
|
669
|
+
this.settings.loadProgress.apply(this, [this.loadedPercent]);
|
670
|
+
}
|
671
|
+
},
|
672
|
+
playPause: function() {
|
673
|
+
if (this.playing) this.pause();
|
674
|
+
else this.play();
|
675
|
+
},
|
676
|
+
play: function() {
|
677
|
+
var ios = (/(ipod|iphone|ipad)/i).test(navigator.userAgent);
|
678
|
+
// On iOS this interaction will trigger loading the mp3, so run `init()`.
|
679
|
+
if (ios && this.element.readyState == 0) this.init.apply(this);
|
680
|
+
// If the audio hasn't started preloading, then start it now.
|
681
|
+
// Then set `preload` to `true`, so that any tracks loaded in subsequently are loaded straight away.
|
682
|
+
if (!this.settings.preload) {
|
683
|
+
this.settings.preload = true;
|
684
|
+
this.element.setAttribute('preload', 'auto');
|
685
|
+
container[audiojs].events.trackLoadProgress(this);
|
686
|
+
}
|
687
|
+
this.playing = true;
|
688
|
+
this.element.play();
|
689
|
+
this.settings.play.apply(this);
|
690
|
+
},
|
691
|
+
pause: function() {
|
692
|
+
this.playing = false;
|
693
|
+
this.element.pause();
|
694
|
+
this.settings.pause.apply(this);
|
695
|
+
},
|
696
|
+
setVolume: function(v) {
|
697
|
+
this.element.volume = v;
|
698
|
+
},
|
699
|
+
trackEnded: function(e) {
|
700
|
+
this.skipTo.apply(this, [0]);
|
701
|
+
if (!this.settings.loop) this.pause.apply(this);
|
702
|
+
this.settings.trackEnded.apply(this);
|
703
|
+
}
|
704
|
+
}
|
705
|
+
|
706
|
+
// **getElementsByClassName**
|
707
|
+
// Having to rely on `getElementsByTagName` is pretty inflexible internally, so a modified version of Dustin Diaz's `getElementsByClassName` has been included.
|
708
|
+
// This version cleans things up and prefers the native DOM method if it's available.
|
709
|
+
var getByClass = function(searchClass, node) {
|
710
|
+
var matches = [];
|
711
|
+
node = node || document;
|
712
|
+
|
713
|
+
if (node.getElementsByClassName) {
|
714
|
+
matches = node.getElementsByClassName(searchClass);
|
715
|
+
} else {
|
716
|
+
var i, l,
|
717
|
+
els = node.getElementsByTagName("*"),
|
718
|
+
pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
|
719
|
+
|
720
|
+
for (i = 0, l = els.length; i < l; i++) {
|
721
|
+
if (pattern.test(els[i].className)) {
|
722
|
+
matches.push(els[i]);
|
723
|
+
}
|
724
|
+
}
|
725
|
+
}
|
726
|
+
return matches.length > 1 ? matches : matches[0];
|
727
|
+
};
|
728
|
+
// The global variable names are passed in here and can be changed if they conflict with anything else.
|
729
|
+
})('audiojs', 'audiojsInstance', this);
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rails-audiojs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- syossan27
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: railties
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: vendorer
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tzinfo
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sprockets-rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Audio.js on Rails Asset Pipeline
|
70
|
+
email:
|
71
|
+
- wisdom1027@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- README.markdown
|
77
|
+
- Rakefile
|
78
|
+
- lib/audiojs/rails.rb
|
79
|
+
- lib/audiojs/rails/version.rb
|
80
|
+
- test/dummy/app/assets/javascripts/application.js
|
81
|
+
- test/dummy/config.ru
|
82
|
+
- test/dummy/config/application.rb
|
83
|
+
- test/dummy/config/boot.rb
|
84
|
+
- test/dummy/config/environment.rb
|
85
|
+
- test/dummy/config/initializers/secret_token.rb
|
86
|
+
- test/dummy/config/routes.rb
|
87
|
+
- test/rails_audiojs_test.rb
|
88
|
+
- test/test_helper.rb
|
89
|
+
- vendor/assets/javascripts/audiojs-player-graphics.gif
|
90
|
+
- vendor/assets/javascripts/audiojs.js.erb
|
91
|
+
- vendor/assets/javascripts/audiojs.swf
|
92
|
+
homepage: https://github.com/syossan27/rails-audiojs
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.4.5.1
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: audio.js is a drop-in javascript library that allows HTML5's <audio> tag
|
116
|
+
to be used anywhere.
|
117
|
+
test_files:
|
118
|
+
- test/dummy/app/assets/javascripts/application.js
|
119
|
+
- test/dummy/config/application.rb
|
120
|
+
- test/dummy/config/boot.rb
|
121
|
+
- test/dummy/config/environment.rb
|
122
|
+
- test/dummy/config/initializers/secret_token.rb
|
123
|
+
- test/dummy/config/routes.rb
|
124
|
+
- test/dummy/config.ru
|
125
|
+
- test/rails_audiojs_test.rb
|
126
|
+
- test/test_helper.rb
|