├── .gitignore
├── Gruntfile.js
├── HISTORY.md
├── LICENSE
├── README.md
├── bower.json
├── bower_components
└── assert
│ ├── .bower.json
│ ├── HISTORY.md
│ ├── README.md
│ ├── assert.js
│ ├── component.json
│ └── test
│ ├── index.html
│ └── test-assert.js
├── dist
├── videojs-playlists.js
└── videojs-playlists.min.js
├── example
└── index.html
├── lib
└── videojs-playlists.js
├── package.json
└── test
├── index.html
└── videojs-playlists.test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | components
4 | reports
5 | .idea
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | grunt.initConfig({
3 | info: grunt.file.readJSON('bower.json'),
4 | meta: {
5 | banner: '/*!\n'+
6 | ' * <%= info.name %> - <%= info.description %>\n'+
7 | ' * v<%= info.version %>\n'+
8 | ' * <%= info.homepage %>\n'+
9 | ' * copyright <%= info.copyright %> <%= grunt.template.today("yyyy") %>\n'+
10 | ' * <%= info.license %> License\n'+
11 | '*/\n'
12 | },
13 | jshint: {
14 | main: [
15 | 'Gruntfile.js',
16 | 'bower.json',
17 | 'lib/**/*.js',
18 | 'test/*.js'
19 | ]
20 | },
21 | concat: {
22 | options: {
23 | banner: '<%= meta.banner %>'
24 | },
25 | dist: {
26 | src: 'lib/videojs-playlists.js',
27 | dest: 'dist/videojs-playlists.js'
28 | }
29 | },
30 | uglify: {
31 | options: {
32 | banner: '<%= meta.banner %>'
33 | },
34 | dist: {
35 | src: 'dist/videojs-playlists.js',
36 | dest: 'dist/videojs-playlists.min.js'
37 | }
38 | },
39 | watch: {
40 | main: {
41 | files: '<%= jshint.main %>',
42 | tasks: 'default',
43 | options: {
44 | livereload: true
45 | }
46 | },
47 | examples: {
48 | files: [
49 | 'example/*'
50 | ],
51 | options: {
52 | livereload: true
53 | }
54 | },
55 | ci: {
56 | files: [
57 | 'test/index.html'
58 | ],
59 | tasks: 'default'
60 | }
61 | },
62 | mocha: {
63 | all: {
64 | src: 'test/index.html',
65 | options: {
66 | run: true
67 | }
68 | }
69 | },
70 | plato: {
71 | main: {
72 | files: {
73 | 'reports': ['lib/*.js']
74 | }
75 | }
76 | },
77 | connect: {
78 | server:{
79 | port: 8000,
80 | base: '.'
81 | },
82 | plato: {
83 | port: 8000,
84 | base: 'reports',
85 | options: {
86 | keepalive: true
87 | }
88 | }
89 | }
90 | });
91 | grunt.loadNpmTasks('grunt-contrib-jshint');
92 | grunt.loadNpmTasks('grunt-contrib-concat');
93 | grunt.loadNpmTasks('grunt-contrib-watch');
94 | grunt.loadNpmTasks('grunt-contrib-uglify');
95 | grunt.loadNpmTasks('grunt-contrib-connect');
96 | grunt.loadNpmTasks('grunt-mocha');
97 | grunt.loadNpmTasks('grunt-plato');
98 | grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
99 | grunt.registerTask('dev', ['connect:server', 'watch']);
100 | grunt.registerTask('ci', ['connect:server', 'watch:ci']);
101 | grunt.registerTask('reports', ['plato', 'connect:plato']);
102 | };
103 |
--------------------------------------------------------------------------------
/HISTORY.md:
--------------------------------------------------------------------------------
1 | 0.2.0 / 2013-11-20
2 | ==================
3 |
4 | * Fixed issue which avoided the playlist to work with latest versions of videojs
5 |
6 |
7 | 0.1.1 / 2013-08-26
8 | ==================
9 |
10 | * Fixed issue with iOS devices in which the plugin won't work
11 |
12 | 0.1.0 / 2013-07-08
13 | ==================
14 |
15 | * added example, updated gruntfile
16 | * added option to pass in function to get video source (for use with s3 tokens)
17 | * Resume on finish & next/prev
18 | * Addding demo to readme
19 | * removed example in favor of demo
20 | * changed alerts to console.logs
21 | * Created demo
22 | * initial commit
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | (The MIT License)
2 |
3 | Copyright (c) 2013 Antonio Laguna
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | 'Software'), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #videojs-playlists
2 |
3 | Sexy Playlists for VideoJS.
4 |
5 | ##Installation
6 |
7 | ###Bower
8 |
9 | `bower install videojs-playlists`
10 |
11 | ###Manual Download
12 |
13 | - [Development]()
14 | - [Production]()
15 |
16 | ##Usage
17 |
18 | ### Initialize playList
19 |
20 | In order to initialize `playList` you need to pass an array of videos with this structure:
21 |
22 | ```js
23 | videos = [
24 | {
25 | src : [
26 | 'http://stream.flowplayer.org/bauhaus/624x260.webm',
27 | 'http://stream.flowplayer.org/bauhaus/624x260.mp4',
28 | 'http://stream.flowplayer.org/bauhaus/624x260.ogv'
29 | ],
30 | poster : '',
31 | title : 'Whales'
32 | },
33 | {
34 | src : [
35 | 'http://vjs.zencdn.net/v/oceans.mp4',
36 | 'http://vjs.zencdn.net/v/oceans.webm'
37 | ],
38 | poster : 'http://www.videojs.com/img/poster.jpg',
39 | title : 'Ocean'
40 | }
41 | ];
42 | ```
43 |
44 | Now, when videos plays they automatically jump to the next one. You also gain a couple of methods
45 |
46 | ### Jump to video
47 |
48 | Use `player.playList(index)` to jump to a video into the playlist.
49 |
50 | ### next
51 |
52 | VideoJS receives a `next()` function which put in place the next video.
53 |
54 | ### prev
55 |
56 | VideoJS receives a `prev()` function which put in place the previous video.
57 |
58 | ### Events
59 |
60 |
61 | Name | Description |
62 | next | Fired when you use the `next()` function or when one video finish and the next starts. |
63 | prev | Fired when you use the `prev()` function. |
64 | lastVideoEnded | Fired when the playlist has finished. |
65 |
66 |
67 | A [demo](http://belelros.github.io/videojs-playLists/) is now available to showcase what you can create with this plugin.
68 |
69 | ##Pending
70 |
71 | Pass video parameter to `next` and `prev` events. That should need to rewrite the trigger function from videojs since
72 | doesn't allow passing events.
73 |
74 | As a workaround, the `player.pl.current` is updated with the actual index and `player.pl.currentVideo` contains the
75 | video object.
76 |
77 | ##Development
78 |
79 | ###Requirements
80 |
81 | - node and npm
82 | - bower `npm install -g bower`
83 | - grunt `npm install -g grunt-cli`
84 |
85 | ###Setup
86 |
87 | - `npm install`
88 | - `bower install`
89 |
90 | ###Run
91 |
92 | `grunt dev`
93 |
94 | or for just running tests on file changes:
95 |
96 | `grunt ci`
97 |
98 | ###Tests
99 |
100 | `grunt mocha`
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "videojs-playlists",
3 | "description": "Playlists done right for Videojs",
4 | "version": "0.2.0",
5 | "homepage": "",
6 | "license": "MIT",
7 | "copyright": "Antonio Laguna",
8 | "main": "dist/videojs-playlists.js",
9 | "dependencies": {
10 | },
11 | "devDependencies": {
12 | "assert": "*"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/bower_components/assert/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "assert",
3 | "version": "0.0.1",
4 | "main": "./assert.js",
5 | "homepage": "https://github.com/jgallen23/assert",
6 | "_release": "0.0.1",
7 | "_resolution": {
8 | "type": "version",
9 | "tag": "0.0.1",
10 | "commit": "d713c8c0d007c22985f92bf4c0aa1ab5688ce187"
11 | },
12 | "_source": "git://github.com/jgallen23/assert.git",
13 | "_target": "*",
14 | "_originalSource": "assert"
15 | }
--------------------------------------------------------------------------------
/bower_components/assert/HISTORY.md:
--------------------------------------------------------------------------------
1 |
2 | 0.0.1 / 2012-12-06
3 | ==================
4 |
5 | * added component.json for bower
6 | * add Object.create comatibile for issue #1
7 | * update assert to v0.8.1
8 | * fix README.md
9 | * to make it perfect: s/the both-sides/both sides/
10 | * Assert to assert
11 | * updates README
12 | * add README.md
13 | * add index.html for browser test
14 | * fix replace for browser
15 | * mod copyright
16 | * add common object instead of require('common')
17 | * semmicolon
18 | * add test-assert.js
19 | * remove case of buffer(browser dosen't has)
20 | * define util.inherits instead of require('util')
21 | * export assert to global or module
22 | * modefy license
23 | * initial commit
24 |
--------------------------------------------------------------------------------
/bower_components/assert/README.md:
--------------------------------------------------------------------------------
1 | # assert.js
2 |
3 | assert.js is a port of the Node.js standard assertion library for the browser.
4 | The original code and tests are from Node.js, and have been modified to be browser compatible.
5 |
6 | For example, you can use it with [Mocha](http://visionmedia.github.com/mocha/) to perform tests
7 | on the **both sides** (server-side and client-side). Mocha does not supply it's own assertion library.
8 |
9 | ## run the same tests on both the client-side and server-side
10 |
11 | You can use the standard assert module when running mocha on Node.js.
12 |
13 | The same tests will run in the browser if you use this library.
14 |
15 | ## how to use
16 |
17 | ```html
18 |
19 |
20 |
21 | ```
22 |
23 | ## running test of this library
24 |
25 | ### browser
26 | open ```test/index.html``` in your browser,
27 | and see the console.
28 |
29 | ### node.js
30 |
31 | ```shell
32 | > node test/test-assert.js
33 | All OK
34 | ```
35 |
36 | ## license
37 |
38 | MIT (same as Node.js)
--------------------------------------------------------------------------------
/bower_components/assert/assert.js:
--------------------------------------------------------------------------------
1 | // http://wiki.commonjs.org/wiki/Unit_Testing/1.0
2 | //
3 | // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
4 | //
5 | // Copyright (c) 2011 Jxck
6 | //
7 | // Originally from node.js (http://nodejs.org)
8 | // Copyright Joyent, Inc.
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the 'Software'), to
12 | // deal in the Software without restriction, including without limitation the
13 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
14 | // sell copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | (function(global) {
28 |
29 | // Object.create compatible in IE
30 | var create = Object.create || function(p) {
31 | if (!p) throw Error('no type');
32 | function f() {};
33 | f.prototype = p;
34 | return new f();
35 | };
36 |
37 | // UTILITY
38 | var util = {
39 | inherits: function(ctor, superCtor) {
40 | ctor.super_ = superCtor;
41 | ctor.prototype = create(superCtor.prototype, {
42 | constructor: {
43 | value: ctor,
44 | enumerable: false,
45 | writable: true,
46 | configurable: true
47 | }
48 | });
49 | }
50 | };
51 |
52 | var pSlice = Array.prototype.slice;
53 |
54 | // 1. The assert module provides functions that throw
55 | // AssertionError's when particular conditions are not met. The
56 | // assert module must conform to the following interface.
57 |
58 | var assert = ok;
59 |
60 | global['assert'] = assert;
61 |
62 | if (typeof module === 'object' && typeof module.exports === 'object') {
63 | module.exports = assert;
64 | };
65 |
66 | // 2. The AssertionError is defined in assert.
67 | // new assert.AssertionError({ message: message,
68 | // actual: actual,
69 | // expected: expected })
70 |
71 | assert.AssertionError = function AssertionError(options) {
72 | this.name = 'AssertionError';
73 | this.message = options.message;
74 | this.actual = options.actual;
75 | this.expected = options.expected;
76 | this.operator = options.operator;
77 | var stackStartFunction = options.stackStartFunction || fail;
78 |
79 | if (Error.captureStackTrace) {
80 | Error.captureStackTrace(this, stackStartFunction);
81 | }
82 | };
83 | util.inherits(assert.AssertionError, Error);
84 |
85 | function replacer(key, value) {
86 | if (value === undefined) {
87 | return '' + value;
88 | }
89 | if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) {
90 | return value.toString();
91 | }
92 | if (typeof value === 'function' || value instanceof RegExp) {
93 | return value.toString();
94 | }
95 | return value;
96 | }
97 |
98 | function truncate(s, n) {
99 | if (typeof s == 'string') {
100 | return s.length < n ? s : s.slice(0, n);
101 | } else {
102 | return s;
103 | }
104 | }
105 |
106 | assert.AssertionError.prototype.toString = function() {
107 | if (this.message) {
108 | return [this.name + ':', this.message].join(' ');
109 | } else {
110 | return [
111 | this.name + ':',
112 | truncate(JSON.stringify(this.actual, replacer), 128),
113 | this.operator,
114 | truncate(JSON.stringify(this.expected, replacer), 128)
115 | ].join(' ');
116 | }
117 | };
118 |
119 | // assert.AssertionError instanceof Error
120 |
121 | assert.AssertionError.__proto__ = Error.prototype;
122 |
123 | // At present only the three keys mentioned above are used and
124 | // understood by the spec. Implementations or sub modules can pass
125 | // other keys to the AssertionError's constructor - they will be
126 | // ignored.
127 |
128 | // 3. All of the following functions must throw an AssertionError
129 | // when a corresponding condition is not met, with a message that
130 | // may be undefined if not provided. All assertion methods provide
131 | // both the actual and expected values to the assertion error for
132 | // display purposes.
133 |
134 | function fail(actual, expected, message, operator, stackStartFunction) {
135 | throw new assert.AssertionError({
136 | message: message,
137 | actual: actual,
138 | expected: expected,
139 | operator: operator,
140 | stackStartFunction: stackStartFunction
141 | });
142 | }
143 |
144 | // EXTENSION! allows for well behaved errors defined elsewhere.
145 | assert.fail = fail;
146 |
147 | // 4. Pure assertion tests whether a value is truthy, as determined
148 | // by !!guard.
149 | // assert.ok(guard, message_opt);
150 | // This statement is equivalent to assert.equal(true, !!guard,
151 | // message_opt);. To test strictly for the value true, use
152 | // assert.strictEqual(true, guard, message_opt);.
153 |
154 | function ok(value, message) {
155 | if (!!!value) fail(value, true, message, '==', assert.ok);
156 | }
157 | assert.ok = ok;
158 |
159 | // 5. The equality assertion tests shallow, coercive equality with
160 | // ==.
161 | // assert.equal(actual, expected, message_opt);
162 |
163 | assert.equal = function equal(actual, expected, message) {
164 | if (actual != expected) fail(actual, expected, message, '==', assert.equal);
165 | };
166 |
167 | // 6. The non-equality assertion tests for whether two objects are not equal
168 | // with != assert.notEqual(actual, expected, message_opt);
169 |
170 | assert.notEqual = function notEqual(actual, expected, message) {
171 | if (actual == expected) {
172 | fail(actual, expected, message, '!=', assert.notEqual);
173 | }
174 | };
175 |
176 | // 7. The equivalence assertion tests a deep equality relation.
177 | // assert.deepEqual(actual, expected, message_opt);
178 |
179 | assert.deepEqual = function deepEqual(actual, expected, message) {
180 | if (!_deepEqual(actual, expected)) {
181 | fail(actual, expected, message, 'deepEqual', assert.deepEqual);
182 | }
183 | };
184 |
185 | function _deepEqual(actual, expected) {
186 | // 7.1. All identical values are equivalent, as determined by ===.
187 | if (actual === expected) {
188 | return true;
189 |
190 | // } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
191 | // if (actual.length != expected.length) return false;
192 | //
193 | // for (var i = 0; i < actual.length; i++) {
194 | // if (actual[i] !== expected[i]) return false;
195 | // }
196 | //
197 | // return true;
198 | //
199 | // 7.2. If the expected value is a Date object, the actual value is
200 | // equivalent if it is also a Date object that refers to the same time.
201 | } else if (actual instanceof Date && expected instanceof Date) {
202 | return actual.getTime() === expected.getTime();
203 |
204 | // 7.3 If the expected value is a RegExp object, the actual value is
205 | // equivalent if it is also a RegExp object with the same source and
206 | // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
207 | } else if (actual instanceof RegExp && expected instanceof RegExp) {
208 | return actual.source === expected.source &&
209 | actual.global === expected.global &&
210 | actual.multiline === expected.multiline &&
211 | actual.lastIndex === expected.lastIndex &&
212 | actual.ignoreCase === expected.ignoreCase;
213 |
214 | // 7.4. Other pairs that do not both pass typeof value == 'object',
215 | // equivalence is determined by ==.
216 | } else if (typeof actual != 'object' && typeof expected != 'object') {
217 | return actual == expected;
218 |
219 | // 7.5 For all other Object pairs, including Array objects, equivalence is
220 | // determined by having the same number of owned properties (as verified
221 | // with Object.prototype.hasOwnProperty.call), the same set of keys
222 | // (although not necessarily the same order), equivalent values for every
223 | // corresponding key, and an identical 'prototype' property. Note: this
224 | // accounts for both named and indexed properties on Arrays.
225 | } else {
226 | return objEquiv(actual, expected);
227 | }
228 | }
229 |
230 | function isUndefinedOrNull(value) {
231 | return value === null || value === undefined;
232 | }
233 |
234 | function isArguments(object) {
235 | return Object.prototype.toString.call(object) == '[object Arguments]';
236 | }
237 |
238 | function objEquiv(a, b) {
239 | if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
240 | return false;
241 | // an identical 'prototype' property.
242 | if (a.prototype !== b.prototype) return false;
243 | //~~~I've managed to break Object.keys through screwy arguments passing.
244 | // Converting to array solves the problem.
245 | if (isArguments(a)) {
246 | if (!isArguments(b)) {
247 | return false;
248 | }
249 | a = pSlice.call(a);
250 | b = pSlice.call(b);
251 | return _deepEqual(a, b);
252 | }
253 | try {
254 | var ka = Object.keys(a),
255 | kb = Object.keys(b),
256 | key, i;
257 | } catch (e) {//happens when one is a string literal and the other isn't
258 | return false;
259 | }
260 | // having the same number of owned properties (keys incorporates
261 | // hasOwnProperty)
262 | if (ka.length != kb.length)
263 | return false;
264 | //the same set of keys (although not necessarily the same order),
265 | ka.sort();
266 | kb.sort();
267 | //~~~cheap key test
268 | for (i = ka.length - 1; i >= 0; i--) {
269 | if (ka[i] != kb[i])
270 | return false;
271 | }
272 | //equivalent values for every corresponding key, and
273 | //~~~possibly expensive deep test
274 | for (i = ka.length - 1; i >= 0; i--) {
275 | key = ka[i];
276 | if (!_deepEqual(a[key], b[key])) return false;
277 | }
278 | return true;
279 | }
280 |
281 | // 8. The non-equivalence assertion tests for any deep inequality.
282 | // assert.notDeepEqual(actual, expected, message_opt);
283 |
284 | assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
285 | if (_deepEqual(actual, expected)) {
286 | fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
287 | }
288 | };
289 |
290 | // 9. The strict equality assertion tests strict equality, as determined by ===.
291 | // assert.strictEqual(actual, expected, message_opt);
292 |
293 | assert.strictEqual = function strictEqual(actual, expected, message) {
294 | if (actual !== expected) {
295 | fail(actual, expected, message, '===', assert.strictEqual);
296 | }
297 | };
298 |
299 | // 10. The strict non-equality assertion tests for strict inequality, as
300 | // determined by !==. assert.notStrictEqual(actual, expected, message_opt);
301 |
302 | assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
303 | if (actual === expected) {
304 | fail(actual, expected, message, '!==', assert.notStrictEqual);
305 | }
306 | };
307 |
308 | function expectedException(actual, expected) {
309 | if (!actual || !expected) {
310 | return false;
311 | }
312 |
313 | if (expected instanceof RegExp) {
314 | return expected.test(actual);
315 | } else if (actual instanceof expected) {
316 | return true;
317 | } else if (expected.call({}, actual) === true) {
318 | return true;
319 | }
320 |
321 | return false;
322 | }
323 |
324 | function _throws(shouldThrow, block, expected, message) {
325 | var actual;
326 |
327 | if (typeof expected === 'string') {
328 | message = expected;
329 | expected = null;
330 | }
331 |
332 | try {
333 | block();
334 | } catch (e) {
335 | actual = e;
336 | }
337 |
338 | message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
339 | (message ? ' ' + message : '.');
340 |
341 | if (shouldThrow && !actual) {
342 | fail('Missing expected exception' + message);
343 | }
344 |
345 | if (!shouldThrow && expectedException(actual, expected)) {
346 | fail('Got unwanted exception' + message);
347 | }
348 |
349 | if ((shouldThrow && actual && expected &&
350 | !expectedException(actual, expected)) || (!shouldThrow && actual)) {
351 | throw actual;
352 | }
353 | }
354 |
355 | // 11. Expected to throw an error:
356 | // assert.throws(block, Error_opt, message_opt);
357 |
358 | assert.throws = function(block, /*optional*/error, /*optional*/message) {
359 | _throws.apply(this, [true].concat(pSlice.call(arguments)));
360 | };
361 |
362 | // EXTENSION! This is annoying to write outside this module.
363 | assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
364 | _throws.apply(this, [false].concat(pSlice.call(arguments)));
365 | };
366 |
367 | assert.ifError = function(err) { if (err) {throw err;}};
368 |
369 | })(this);
370 |
371 |
--------------------------------------------------------------------------------
/bower_components/assert/component.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "assert",
3 | "version": "0.0.1",
4 | "main": "./assert.js"
5 | }
6 |
--------------------------------------------------------------------------------
/bower_components/assert/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Test Assert
5 |
6 |
7 |
8 |
9 | Test Assert
10 | Please see the console output
11 | If all test has passed, you can see All OK
12 |
13 |
14 |
--------------------------------------------------------------------------------
/bower_components/assert/test/test-assert.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011 Jxck
2 | //
3 | // Originally from node.js (http://nodejs.org)
4 | // Copyright Joyent, Inc. and other Node contributors.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a
7 | // copy of this software and associated documentation files (the
8 | // "Software"), to deal in the Software without restriction, including
9 | // without limitation the rights to use, copy, modify, merge, publish,
10 | // distribute, sublicense, and/or sell copies of the Software, and to permit
11 | // persons to whom the Software is furnished to do so, subject to the
12 | // following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be included
15 | // in all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 | // USE OR OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | if(typeof require === 'function') {
26 | var assert = require('../assert');
27 | var a = require('../assert');
28 | } else {
29 | var a = assert;
30 | };
31 |
32 | var common = {
33 | protoCtrChain: function(o) {
34 | var result = [];
35 | for (; o; o = o.__proto__) { result.push(o.constructor); }
36 | return result.join();
37 | },
38 | indirectInstanceOf: function(obj, cls) {
39 | if (obj instanceof cls) { return true; }
40 | var clsChain = protoCtrChain(cls.prototype);
41 | var objChain = protoCtrChain(obj);
42 | return objChain.slice(-clsChain.length) === clsChain;
43 | }
44 | };
45 |
46 | function makeBlock(f) {
47 | var args = Array.prototype.slice.call(arguments, 1);
48 | return function() {
49 | return f.apply(this, args);
50 | };
51 | }
52 |
53 | assert.ok(common.indirectInstanceOf(a.AssertionError.prototype, Error),
54 | 'a.AssertionError instanceof Error');
55 |
56 | assert.throws(makeBlock(a, false), a.AssertionError, 'ok(false)');
57 |
58 | assert.doesNotThrow(makeBlock(a, true), a.AssertionError, 'ok(true)');
59 |
60 | assert.doesNotThrow(makeBlock(a, 'test', 'ok(\'test\')'));
61 |
62 | assert.throws(makeBlock(a.ok, false),
63 | a.AssertionError, 'ok(false)');
64 |
65 | assert.doesNotThrow(makeBlock(a.ok, true),
66 | a.AssertionError, 'ok(true)');
67 |
68 | assert.doesNotThrow(makeBlock(a.ok, 'test'), 'ok(\'test\')');
69 |
70 | assert.throws(makeBlock(a.equal, true, false), a.AssertionError, 'equal');
71 |
72 | assert.doesNotThrow(makeBlock(a.equal, null, null), 'equal');
73 |
74 | assert.doesNotThrow(makeBlock(a.equal, undefined, undefined), 'equal');
75 |
76 | assert.doesNotThrow(makeBlock(a.equal, null, undefined), 'equal');
77 |
78 | assert.doesNotThrow(makeBlock(a.equal, true, true), 'equal');
79 |
80 | assert.doesNotThrow(makeBlock(a.equal, 2, '2'), 'equal');
81 |
82 | assert.doesNotThrow(makeBlock(a.notEqual, true, false), 'notEqual');
83 |
84 | assert.throws(makeBlock(a.notEqual, true, true),
85 | a.AssertionError, 'notEqual');
86 |
87 | assert.throws(makeBlock(a.strictEqual, 2, '2'),
88 | a.AssertionError, 'strictEqual');
89 |
90 | assert.throws(makeBlock(a.strictEqual, null, undefined),
91 | a.AssertionError, 'strictEqual');
92 |
93 | assert.doesNotThrow(makeBlock(a.notStrictEqual, 2, '2'), 'notStrictEqual');
94 |
95 | // deepEquals joy!
96 | // 7.2
97 | assert.doesNotThrow(makeBlock(a.deepEqual, new Date(2000, 3, 14),
98 | new Date(2000, 3, 14)), 'deepEqual date');
99 |
100 | assert.throws(makeBlock(a.deepEqual, new Date(), new Date(2000, 3, 14)),
101 | a.AssertionError,
102 | 'deepEqual date');
103 |
104 | // 7.3
105 | assert.doesNotThrow(makeBlock(a.deepEqual, /a/, /a/));
106 | assert.doesNotThrow(makeBlock(a.deepEqual, /a/g, /a/g));
107 | assert.doesNotThrow(makeBlock(a.deepEqual, /a/i, /a/i));
108 | assert.doesNotThrow(makeBlock(a.deepEqual, /a/m, /a/m));
109 | assert.doesNotThrow(makeBlock(a.deepEqual, /a/igm, /a/igm));
110 | assert.throws(makeBlock(a.deepEqual, /ab/, /a/));
111 | assert.throws(makeBlock(a.deepEqual, /a/g, /a/));
112 | assert.throws(makeBlock(a.deepEqual, /a/i, /a/));
113 | assert.throws(makeBlock(a.deepEqual, /a/m, /a/));
114 | assert.throws(makeBlock(a.deepEqual, /a/igm, /a/im));
115 |
116 | var re1 = /a/;
117 | re1.lastIndex = 3;
118 | assert.throws(makeBlock(a.deepEqual, re1, /a/));
119 |
120 |
121 | // 7.4
122 | assert.doesNotThrow(makeBlock(a.deepEqual, 4, '4'), 'deepEqual == check');
123 | assert.doesNotThrow(makeBlock(a.deepEqual, true, 1), 'deepEqual == check');
124 | assert.throws(makeBlock(a.deepEqual, 4, '5'),
125 | a.AssertionError,
126 | 'deepEqual == check');
127 |
128 | // 7.5
129 | // having the same number of owned properties && the same set of keys
130 | assert.doesNotThrow(makeBlock(a.deepEqual, {a: 4}, {a: 4}));
131 | assert.doesNotThrow(makeBlock(a.deepEqual, {a: 4, b: '2'}, {a: 4, b: '2'}));
132 | assert.doesNotThrow(makeBlock(a.deepEqual, [4], ['4']));
133 | assert.throws(makeBlock(a.deepEqual, {a: 4}, {a: 4, b: true}),
134 | a.AssertionError);
135 | assert.doesNotThrow(makeBlock(a.deepEqual, ['a'], {0: 'a'}));
136 | //(although not necessarily the same order),
137 | assert.doesNotThrow(makeBlock(a.deepEqual, {a: 4, b: '1'}, {b: '1', a: 4}));
138 | var a1 = [1, 2, 3];
139 | var a2 = [1, 2, 3];
140 | a1.a = 'test';
141 | a1.b = true;
142 | a2.b = true;
143 | a2.a = 'test';
144 | assert.throws(makeBlock(a.deepEqual, Object.keys(a1), Object.keys(a2)),
145 | a.AssertionError);
146 | assert.doesNotThrow(makeBlock(a.deepEqual, a1, a2));
147 |
148 | // having an identical prototype property
149 | var nbRoot = {
150 | toString: function() { return this.first + ' ' + this.last; }
151 | };
152 |
153 | function nameBuilder(first, last) {
154 | this.first = first;
155 | this.last = last;
156 | return this;
157 | }
158 | nameBuilder.prototype = nbRoot;
159 |
160 | function nameBuilder2(first, last) {
161 | this.first = first;
162 | this.last = last;
163 | return this;
164 | }
165 | nameBuilder2.prototype = nbRoot;
166 |
167 | var nb1 = new nameBuilder('Ryan', 'Dahl');
168 | var nb2 = new nameBuilder2('Ryan', 'Dahl');
169 |
170 | assert.doesNotThrow(makeBlock(a.deepEqual, nb1, nb2));
171 |
172 | nameBuilder2.prototype = Object;
173 | nb2 = new nameBuilder2('Ryan', 'Dahl');
174 | assert.throws(makeBlock(a.deepEqual, nb1, nb2), a.AssertionError);
175 |
176 | // String literal + object blew up my implementation...
177 | assert.throws(makeBlock(a.deepEqual, 'a', {}), a.AssertionError);
178 |
179 | // Testing the throwing
180 | function thrower(errorConstructor) {
181 | throw new errorConstructor('test');
182 | }
183 | var aethrow = makeBlock(thrower, a.AssertionError);
184 | aethrow = makeBlock(thrower, a.AssertionError);
185 |
186 | // the basic calls work
187 | assert.throws(makeBlock(thrower, a.AssertionError),
188 | a.AssertionError, 'message');
189 | assert.throws(makeBlock(thrower, a.AssertionError), a.AssertionError);
190 | assert.throws(makeBlock(thrower, a.AssertionError));
191 |
192 | // if not passing an error, catch all.
193 | assert.throws(makeBlock(thrower, TypeError));
194 |
195 | // when passing a type, only catch errors of the appropriate type
196 | var threw = false;
197 | try {
198 | a.throws(makeBlock(thrower, TypeError), a.AssertionError);
199 | } catch (e) {
200 | threw = true;
201 | assert.ok(e instanceof TypeError, 'type');
202 | }
203 | assert.equal(true, threw,
204 | 'a.throws with an explicit error is eating extra errors',
205 | a.AssertionError);
206 | threw = false;
207 |
208 | // doesNotThrow should pass through all errors
209 | try {
210 | a.doesNotThrow(makeBlock(thrower, TypeError), a.AssertionError);
211 | } catch (e) {
212 | threw = true;
213 | assert.ok(e instanceof TypeError);
214 | }
215 | assert.equal(true, threw,
216 | 'a.doesNotThrow with an explicit error is eating extra errors');
217 |
218 | // key difference is that throwing our correct error makes an assertion error
219 | try {
220 | a.doesNotThrow(makeBlock(thrower, TypeError), TypeError);
221 | } catch (e) {
222 | threw = true;
223 | assert.ok(e instanceof a.AssertionError);
224 | }
225 | assert.equal(true, threw,
226 | 'a.doesNotThrow is not catching type matching errors');
227 |
228 | assert.throws(function() {assert.ifError(new Error('test error'))});
229 | assert.doesNotThrow(function() {assert.ifError(null)});
230 | assert.doesNotThrow(function() {assert.ifError()});
231 |
232 | // make sure that validating using constructor really works
233 | threw = false;
234 | try {
235 | assert.throws(
236 | function() {
237 | throw ({});
238 | },
239 | Array
240 | );
241 | } catch (e) {
242 | threw = true;
243 | }
244 | assert.ok(threw, 'wrong constructor validation');
245 |
246 | // use a RegExp to validate error message
247 | a.throws(makeBlock(thrower, TypeError), /test/);
248 |
249 | // use a fn to validate error object
250 | a.throws(makeBlock(thrower, TypeError), function(err) {
251 | if ((err instanceof TypeError) && /test/.test(err)) {
252 | return true;
253 | }
254 | });
255 |
256 |
257 | // GH-207. Make sure deepEqual doesn't loop forever on circular refs
258 |
259 | var b = {};
260 | b.b = b;
261 |
262 | var c = {};
263 | c.b = c;
264 |
265 | var gotError = false;
266 | try {
267 | assert.deepEqual(b, c);
268 | } catch (e) {
269 | gotError = true;
270 | }
271 |
272 | console.log('All OK');
273 | assert.ok(gotError);
274 |
275 |
276 | // #217
277 | function testAssertionMessage(actual, expected) {
278 | try {
279 | assert.equal(actual, '');
280 | } catch (e) {
281 | assert.equal(e.toString(),
282 | ['AssertionError:', expected, '==', '""'].join(' '));
283 | }
284 | }
285 | testAssertionMessage(undefined, '"undefined"');
286 | testAssertionMessage(null, 'null');
287 | testAssertionMessage(true, 'true');
288 | testAssertionMessage(false, 'false');
289 | testAssertionMessage(0, '0');
290 | testAssertionMessage(100, '100');
291 | testAssertionMessage(NaN, '"NaN"');
292 | testAssertionMessage(Infinity, '"Infinity"');
293 | testAssertionMessage(-Infinity, '"-Infinity"');
294 | testAssertionMessage('', '""');
295 | testAssertionMessage('foo', '"foo"');
296 | testAssertionMessage([], '[]');
297 | testAssertionMessage([1, 2, 3], '[1,2,3]');
298 | testAssertionMessage(/a/, '"/a/"');
299 | testAssertionMessage(/abc/gim, '"/abc/gim"');
300 | testAssertionMessage(function f() {}, '"function f() {}"');
301 | testAssertionMessage({}, '{}');
302 | testAssertionMessage({a: undefined, b: null}, '{"a":"undefined","b":null}');
303 | testAssertionMessage({a: NaN, b: Infinity, c: -Infinity},
304 | '{"a":"NaN","b":"Infinity","c":"-Infinity"}');
305 |
306 |
--------------------------------------------------------------------------------
/dist/videojs-playlists.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * videojs-playlists - Playlists done right for Videojs
3 | * v0.1.1
4 | *
5 | * copyright Antonio Laguna 2013
6 | * MIT License
7 | */
8 | //videojs-playlists.js
9 | function playList(options,arg){
10 | var player = this;
11 | player.pl = player.pl || {};
12 | var index = parseInt(options,10);
13 |
14 | player.pl._guessVideoType = function(video){
15 | var videoTypes = {
16 | 'webm' : 'video/webm',
17 | 'mp4' : 'video/mp4',
18 | 'ogv' : 'video/ogg'
19 | };
20 | var extension = video.split('.').pop();
21 |
22 | return videoTypes[extension] || '';
23 | };
24 |
25 | player.pl.init = function(videos, options) {
26 | options = options || {};
27 | player.pl.videos = [];
28 | player.pl.current = 0;
29 | player.on('ended', player.pl._videoEnd);
30 |
31 | if (options.getVideoSource) {
32 | player.pl.getVideoSource = options.getVideoSource;
33 | }
34 |
35 | player.pl._addVideos(videos);
36 | };
37 |
38 | player.pl._updatePoster = function(posterURL) {
39 | player.poster(posterURL);
40 | player.removeChild(player.posterImage);
41 | player.posterImage = player.addChild("posterImage");
42 | };
43 |
44 | player.pl._addVideos = function(videos){
45 | for (var i = 0, length = videos.length; i < length; i++){
46 | var aux = [];
47 | for (var j = 0, len = videos[i].src.length; j < len; j++){
48 | aux.push({
49 | type : player.pl._guessVideoType(videos[i].src[j]),
50 | src : videos[i].src[j]
51 | });
52 | }
53 | videos[i].src = aux;
54 | player.pl.videos.push(videos[i]);
55 | }
56 | };
57 |
58 | player.pl._nextPrev = function(func){
59 | var comparison, addendum;
60 |
61 | if (func === 'next'){
62 | comparison = player.pl.videos.length -1;
63 | addendum = 1;
64 | }
65 | else {
66 | comparison = 0;
67 | addendum = -1;
68 | }
69 |
70 | if (player.pl.current !== comparison){
71 | var newIndex = player.pl.current + addendum;
72 | player.pl._setVideo(newIndex);
73 | player.trigger(func, [player.pl.videos[newIndex]]);
74 | }
75 | };
76 |
77 | player.pl._setVideo = function(index){
78 | if (index < player.pl.videos.length){
79 | player.pl.current = index;
80 | player.pl.currentVideo = player.pl.videos[index];
81 |
82 | if (!player.paused()){
83 | player.pl._resumeVideo();
84 | }
85 |
86 | if (player.pl.getVideoSource) {
87 | player.pl.getVideoSource(player.pl.videos[index], function(src, poster) {
88 | player.pl._setVideoSource(src, poster);
89 | });
90 | } else {
91 | player.pl._setVideoSource(player.pl.videos[index].src, player.pl.videos[index].poster);
92 | }
93 | }
94 | };
95 |
96 | player.pl._setVideoSource = function(src, poster) {
97 | player.src(src);
98 | player.pl._updatePoster(poster);
99 | };
100 |
101 | player.pl._resumeVideo = function(){
102 | player.one('loadstart',function(){
103 | player.play();
104 | });
105 | };
106 |
107 | player.pl._videoEnd = function(){
108 | if (player.pl.current === player.pl.videos.length -1){
109 | player.trigger('lastVideoEnded');
110 | }
111 | else {
112 | player.pl._resumeVideo();
113 | player.next();
114 | }
115 | };
116 |
117 | if (options instanceof Array){
118 | player.pl.init(options, arg);
119 | player.pl._setVideo(0);
120 | return player;
121 | }
122 | else if (index === index){ // NaN
123 | player.pl._setVideo(index);
124 | return player;
125 | }
126 | else if (typeof options === 'string' && typeof player.pl[options] !== 'undefined'){
127 | player.pl[options].apply(player);
128 | return player;
129 | }
130 | }
131 |
132 | videojs.Player.prototype.next = function(){
133 | this.pl._nextPrev('next');
134 | return this;
135 | };
136 | videojs.Player.prototype.prev = function(){
137 | this.pl._nextPrev('prev');
138 | return this;
139 | };
140 |
141 | videojs.plugin('playList', playList);
142 |
--------------------------------------------------------------------------------
/dist/videojs-playlists.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * videojs-playlists - Playlists done right for Videojs
3 | * v0.1.1
4 | *
5 | * copyright Antonio Laguna 2013
6 | * MIT License
7 | */
8 | function playList(a,b){var c=this;c.pl=c.pl||{};var d=parseInt(a,10);return c.pl._guessVideoType=function(a){var b={webm:"video/webm",mp4:"video/mp4",ogv:"video/ogg"},c=a.split(".").pop();return b[c]||""},c.pl.init=function(a,b){b=b||{},c.pl.videos=[],c.pl.current=0,c.on("ended",c.pl._videoEnd),b.getVideoSource&&(c.pl.getVideoSource=b.getVideoSource),c.pl._addVideos(a)},c.pl._updatePoster=function(a){c.poster(a),c.removeChild(c.posterImage),c.posterImage=c.addChild("posterImage")},c.pl._addVideos=function(a){for(var b=0,d=a.length;d>b;b++){for(var e=[],f=0,g=a[b].src.length;g>f;f++)e.push({type:c.pl._guessVideoType(a[b].src[f]),src:a[b].src[f]});a[b].src=e,c.pl.videos.push(a[b])}},c.pl._nextPrev=function(a){var b,d;if("next"===a?(b=c.pl.videos.length-1,d=1):(b=0,d=-1),c.pl.current!==b){var e=c.pl.current+d;c.pl._setVideo(e),c.trigger(a,[c.pl.videos[e]])}},c.pl._setVideo=function(a){a
2 |
3 |
4 |
5 | videojs-playlists demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/lib/videojs-playlists.js:
--------------------------------------------------------------------------------
1 | //videojs-playlists.js
2 | function playList(options,arg){
3 | var player = this;
4 | player.pl = player.pl || {};
5 | var index = parseInt(options,10);
6 |
7 | player.pl._guessVideoType = function(video){
8 | var videoTypes = {
9 | 'webm' : 'video/webm',
10 | 'mp4' : 'video/mp4',
11 | 'ogv' : 'video/ogg'
12 | };
13 | var extension = video.split('.').pop();
14 |
15 | return videoTypes[extension] || '';
16 | };
17 |
18 | player.pl.init = function(videos, options) {
19 | options = options || {};
20 | player.pl.videos = [];
21 | player.pl.current = 0;
22 | player.on('ended', player.pl._videoEnd);
23 |
24 | if (options.getVideoSource) {
25 | player.pl.getVideoSource = options.getVideoSource;
26 | }
27 |
28 | player.pl._addVideos(videos);
29 | };
30 |
31 | player.pl._updatePoster = function(posterURL) {
32 | player.poster(posterURL);
33 | player.removeChild(player.posterImage);
34 | player.posterImage = player.addChild("posterImage");
35 | };
36 |
37 | player.pl._addVideos = function(videos){
38 | for (var i = 0, length = videos.length; i < length; i++){
39 | var aux = [];
40 | for (var j = 0, len = videos[i].src.length; j < len; j++){
41 | aux.push({
42 | type : player.pl._guessVideoType(videos[i].src[j]),
43 | src : videos[i].src[j]
44 | });
45 | }
46 | videos[i].src = aux;
47 | player.pl.videos.push(videos[i]);
48 | }
49 | };
50 |
51 | player.pl._nextPrev = function(func){
52 | var comparison, addendum;
53 |
54 | if (func === 'next'){
55 | comparison = player.pl.videos.length -1;
56 | addendum = 1;
57 | }
58 | else {
59 | comparison = 0;
60 | addendum = -1;
61 | }
62 |
63 | if (player.pl.current !== comparison){
64 | var newIndex = player.pl.current + addendum;
65 | player.pl._setVideo(newIndex);
66 | player.trigger(func, [player.pl.videos[newIndex]]);
67 | }
68 | };
69 |
70 | player.pl._setVideo = function(index){
71 | if (index < player.pl.videos.length){
72 | player.pl.current = index;
73 | player.pl.currentVideo = player.pl.videos[index];
74 |
75 | if (!player.paused()){
76 | player.pl._resumeVideo();
77 | }
78 |
79 | if (player.pl.getVideoSource) {
80 | player.pl.getVideoSource(player.pl.videos[index], function(src, poster) {
81 | player.pl._setVideoSource(src, poster);
82 | });
83 | } else {
84 | player.pl._setVideoSource(player.pl.videos[index].src, player.pl.videos[index].poster);
85 | }
86 | }
87 | };
88 |
89 | player.pl._setVideoSource = function(src, poster) {
90 | player.src(src);
91 | player.pl._updatePoster(poster);
92 | };
93 |
94 | player.pl._resumeVideo = function(){
95 | player.one('loadstart',function(){
96 | player.play();
97 | });
98 | };
99 |
100 | player.pl._videoEnd = function(){
101 | if (player.pl.current === player.pl.videos.length -1){
102 | player.trigger('lastVideoEnded');
103 | }
104 | else {
105 | player.pl._resumeVideo();
106 | player.next();
107 | }
108 | };
109 |
110 | if (options instanceof Array){
111 | player.pl.init(options, arg);
112 | player.pl._setVideo(0);
113 | return player;
114 | }
115 | else if (index === index){ // NaN
116 | player.pl._setVideo(index);
117 | return player;
118 | }
119 | else if (typeof options === 'string' && typeof player.pl[options] !== 'undefined'){
120 | player.pl[options].apply(player);
121 | return player;
122 | }
123 | }
124 |
125 | videojs.Player.prototype.next = function(){
126 | this.pl._nextPrev('next');
127 | return this;
128 | };
129 | videojs.Player.prototype.prev = function(){
130 | this.pl._nextPrev('prev');
131 | return this;
132 | };
133 |
134 | videojs.plugin('playList', playList);
135 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "videojs-playlists",
3 | "version": "0.2.0",
4 | "private": true,
5 | "devDependencies": {
6 | "mocha": "1.10.0",
7 | "grunt": "~0.4.1",
8 | "grunt-reloadr": "~0.1.2",
9 | "grunt-mocha": "~0.3.0",
10 | "grunt-contrib-concat": "~0.3.0",
11 | "grunt-contrib-uglify": "~0.2.0",
12 | "grunt-contrib-jshint": "~0.5.4",
13 | "grunt-contrib-connect": "~0.3.0",
14 | "grunt-contrib-watch": "~0.4.3",
15 | "grunt-plato": "~0.2.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | videojs-playlists Tests
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
32 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/test/videojs-playlists.test.js:
--------------------------------------------------------------------------------
1 |
2 | suite('videojs-playlists', function() {
3 | var player, videos, index;
4 | suiteSetup(function(){
5 | videos = [
6 | {
7 | src : [
8 | 'http://stream.flowplayer.org/bauhaus/624x260.webm',
9 | 'http://stream.flowplayer.org/bauhaus/624x260.mp4',
10 | 'http://stream.flowplayer.org/bauhaus/624x260.ogv'
11 | ],
12 | poster : 'http://flowplayer.org/media/img/demos/functional.jpg',
13 | title : 'Whales'
14 | },
15 | {
16 | src : [
17 | 'http://vjs.zencdn.net/v/oceans.mp4',
18 | 'http://vjs.zencdn.net/v/oceans.webm'
19 | ],
20 | poster : 'http://www.videojs.com/img/poster.jpg',
21 | title : 'Whales'
22 | }
23 | ];
24 | player = videojs("example_video_1");
25 | player.playList(videos);
26 | });
27 |
28 | suite('#_init()', function(){
29 | test('should have same videos stored after videos have been loaded',function(){
30 | assert.equal(player.pl.videos.length,videos.length);
31 | });
32 | test('current video should be 0 after init',function(){
33 | assert.equal(player.pl.current,0);
34 | });
35 | });
36 | suite('#playList(index)',function(){
37 | suiteSetup(function(){
38 | index = 1;
39 | player.playList(index);
40 | });
41 | test('current should change on index passing',function(){
42 | assert.equal(player.pl.current,index);
43 | });
44 | test('poster should match video poster',function(){
45 | var poster = $('.vjs-poster').css('background-image').replace('url(','').replace(')','');
46 | assert.equal(poster,videos[index].poster);
47 | });
48 | });
49 | suite('general',function(){
50 | setup(function(){
51 | index = 0;
52 | player.playList(index);
53 | });
54 | test('next video should autostart',function(done){
55 | player.one('loadedmetadata',function(){
56 | var duration = player.duration();
57 | player.currentTime(duration);
58 | });
59 | player.one('next',function(){
60 | done();
61 | });
62 | });
63 | test('last video should fire event',function(done){
64 | player.playList(1);
65 | player.one('loadedmetadata',function(){
66 | var duration = player.duration();
67 | player.currentTime(duration);
68 | });
69 | player.one('lastVideoEnded',function(){
70 | done();
71 | });
72 | });
73 | });
74 | suite('#next()',function(){
75 | setup(function(){
76 | index = 0;
77 | player.playList(index);
78 | });
79 | test('calling next increase the current video index',function(done){
80 | var currentVideo = player.pl.current;
81 | player.one('next',function(){
82 | assert.equal(player.pl.current,currentVideo+1);
83 | done();
84 | });
85 | player.next();
86 | });
87 | test('calling next should fire a \'next\' event',function(done){
88 | player.one('next',function(){
89 | done();
90 | });
91 | player.next();
92 | });
93 | });
94 |
95 | suite('#prev()',function(){
96 | setup(function(){
97 | index = 1;
98 | player.playList(index);
99 | });
100 | test('calling prev decrease the current video index',function(done){
101 | var currentVideo = player.pl.current;
102 | player.one('prev',function(){
103 | assert.equal(player.pl.current,currentVideo-1);
104 | done();
105 | });
106 | player.prev();
107 | });
108 | test('calling prev should fire a \'prev\' event',function(done){
109 | player.one('prev',function(){
110 | done();
111 | });
112 | player.prev();
113 | });
114 | });
115 | });
116 |
--------------------------------------------------------------------------------