├── .gitignore ├── src ├── fonts │ ├── stvideo.eot │ ├── stvideo.ttf │ ├── stvideo.woff │ ├── stvideo.woff2 │ ├── fontello-config.json │ └── stvideo.svg ├── css │ └── stvideo.css └── js │ └── stvideo.js ├── dist ├── fonts │ ├── stvideo.eot │ ├── stvideo.ttf │ ├── stvideo.woff │ ├── stvideo.woff2 │ ├── fontello-config.json │ └── stvideo.svg ├── css │ └── stvideo.css └── js │ ├── stvideo.min.js │ ├── stvideo.min.js.map │ └── stvideo.js ├── .editorconfig ├── package.json ├── .eslintrc.json ├── README.md └── gruntfile.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /__stuff 3 | *.DS_Store 4 | 5 | /assets 6 | /index.html 7 | -------------------------------------------------------------------------------- /src/fonts/stvideo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tstabla/stVideo/HEAD/src/fonts/stvideo.eot -------------------------------------------------------------------------------- /src/fonts/stvideo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tstabla/stVideo/HEAD/src/fonts/stvideo.ttf -------------------------------------------------------------------------------- /dist/fonts/stvideo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tstabla/stVideo/HEAD/dist/fonts/stvideo.eot -------------------------------------------------------------------------------- /dist/fonts/stvideo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tstabla/stVideo/HEAD/dist/fonts/stvideo.ttf -------------------------------------------------------------------------------- /dist/fonts/stvideo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tstabla/stVideo/HEAD/dist/fonts/stvideo.woff -------------------------------------------------------------------------------- /src/fonts/stvideo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tstabla/stVideo/HEAD/src/fonts/stvideo.woff -------------------------------------------------------------------------------- /src/fonts/stvideo.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tstabla/stVideo/HEAD/src/fonts/stvideo.woff2 -------------------------------------------------------------------------------- /dist/fonts/stvideo.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tstabla/stVideo/HEAD/dist/fonts/stvideo.woff2 -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = tab 6 | indent_size = 2 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stVideo", 3 | "version": "0.9.0", 4 | "description": "HTML5 video canvas player. Prevents video fullscreen on iPhone/iPad.", 5 | "author": { 6 | "name": "Tomasz Stabla", 7 | "email": "t.stabla@hotmail.com", 8 | "url": "http://stabla.com" 9 | }, 10 | "main": "dist/js/stVideo.js", 11 | "homepage": "https://github.com/tstabla/stVideo", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/tstabla/stVideo.git" 15 | }, 16 | "license": "MIT", 17 | "keywords": [ 18 | "html5", 19 | "video", 20 | "canvas", 21 | "player", 22 | "simple", 23 | "iphone", 24 | "ipad" 25 | ], 26 | "dependencies": { 27 | }, 28 | "devDependencies": { 29 | "grunt": "~0.4.2", 30 | "grunt-contrib-copy": "*", 31 | "grunt-contrib-concat": "*", 32 | "grunt-contrib-jshint": "*", 33 | "grunt-contrib-uglify": "*", 34 | "grunt-contrib-watch": "*", 35 | "matchdep": "*", 36 | "module": "0.0.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /dist/fonts/fontello-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "css_prefix_text": "icon-", 4 | "css_use_suffix": false, 5 | "hinting": true, 6 | "units_per_em": 1000, 7 | "ascent": 850, 8 | "glyphs": [ 9 | { 10 | "uid": "8489d61496923b1159b01d8a0a7b2df0", 11 | "css": "volume-off", 12 | "code": 59392, 13 | "src": "elusive" 14 | }, 15 | { 16 | "uid": "5d9730dc93976d27eb07914eab50a507", 17 | "css": "volume-down", 18 | "code": 59393, 19 | "src": "elusive" 20 | }, 21 | { 22 | "uid": "b59b3b618699b467541f631edd5a02ed", 23 | "css": "volume", 24 | "code": 59394, 25 | "src": "elusive" 26 | }, 27 | { 28 | "uid": "012ff5762ccb18c16bdfdd6baf187406", 29 | "css": "volume-up", 30 | "code": 59395, 31 | "src": "elusive" 32 | }, 33 | { 34 | "uid": "3711151b8b34536498e2a7f4d5188ed2", 35 | "css": "play", 36 | "code": 61455, 37 | "src": "mfglabs" 38 | }, 39 | { 40 | "uid": "164f35b55c3346b03fa89a711a4f3980", 41 | "css": "pause", 42 | "code": 61454, 43 | "src": "mfglabs" 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /src/fonts/fontello-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "css_prefix_text": "icon-", 4 | "css_use_suffix": false, 5 | "hinting": true, 6 | "units_per_em": 1000, 7 | "ascent": 850, 8 | "glyphs": [ 9 | { 10 | "uid": "8489d61496923b1159b01d8a0a7b2df0", 11 | "css": "volume-off", 12 | "code": 59392, 13 | "src": "elusive" 14 | }, 15 | { 16 | "uid": "5d9730dc93976d27eb07914eab50a507", 17 | "css": "volume-down", 18 | "code": 59393, 19 | "src": "elusive" 20 | }, 21 | { 22 | "uid": "b59b3b618699b467541f631edd5a02ed", 23 | "css": "volume", 24 | "code": 59394, 25 | "src": "elusive" 26 | }, 27 | { 28 | "uid": "012ff5762ccb18c16bdfdd6baf187406", 29 | "css": "volume-up", 30 | "code": 59395, 31 | "src": "elusive" 32 | }, 33 | { 34 | "uid": "3711151b8b34536498e2a7f4d5188ed2", 35 | "css": "play", 36 | "code": 61455, 37 | "src": "mfglabs" 38 | }, 39 | { 40 | "uid": "164f35b55c3346b03fa89a711a4f3980", 41 | "css": "pause", 42 | "code": 61454, 43 | "src": "mfglabs" 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /dist/fonts/stvideo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2016 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/fonts/stvideo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2016 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true, 6 | "node": true, 7 | "mocha": true 8 | }, 9 | "extends": "eslint:recommended", 10 | "parserOptions": { 11 | "sourceType": "module", 12 | "ecmaFeatures": { 13 | "impliedStrict": true 14 | } 15 | }, 16 | "rules": { 17 | "indent": [ 2, 2 ], 18 | "linebreak-style": [ 2, "unix" ], 19 | "quotes": [ 2, "single" ], 20 | "semi": [ 2, "always" ], 21 | "curly": 2, 22 | "brace-style": [2, "1tbs" ], 23 | "camelcase": [ 2, { "properties": "always" } ], 24 | "comma-spacing": [ 2, { "before": false, "after": true } ], 25 | "comma-style": [ 2, "last" ], 26 | "key-spacing": [ 2, { "align": { "beforeColon": true, "afterColon": true, "on": "colon" } } ], 27 | "keyword-spacing": 2, 28 | "block-spacing": 2, 29 | "array-bracket-spacing": [ 2, "always" ], 30 | "object-curly-spacing": [ 2, "always" ], 31 | "computed-property-spacing": [ 2, "always" ], 32 | "space-in-parens": [ 2, "always" ], 33 | "space-before-function-paren": [ 2, "never" ], 34 | "generator-star-spacing": [ 2, "after" ], 35 | "yield-star-spacing": [ 2, "after" ], 36 | "space-infix-ops": 2, 37 | "space-unary-ops": 2, 38 | "spaced-comment": [ 2, "always" ], 39 | "arrow-spacing": [2, { "before": true, "after": true } ], 40 | "arrow-parens": [ 2, "always" ], 41 | "arrow-body-style": [ 2, "always" ], 42 | "no-trailing-spaces": 2, 43 | "no-multiple-empty-lines": [ 2, { "max": 1 } ], 44 | "eol-last": 2, 45 | "valid-jsdoc": 2, 46 | "no-implicit-coercion": [ 2, { "allow": [ "!!" ] } ], 47 | "no-native-reassign": 2, 48 | "wrap-iife": [ 2, "any" ], 49 | "yoda": [ 2, "never" ], 50 | "prefer-const": 2, 51 | "prefer-rest-params": 2, 52 | "prefer-spread": 2, 53 | "object-shorthand": [ 2, "always" ], 54 | "no-array-constructor": 2, 55 | "no-new-object": 2, 56 | "new-cap": 2, 57 | "new-parens": 2, 58 | "no-lonely-if": 2, 59 | "no-use-before-define": 2, 60 | "no-with": 2, 61 | "eqeqeq": [ 2, "smart" ], 62 | "no-unused-vars": [2, {"vars": "all", "args": "none"}] 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [stVideo](https://tstabla.github.io/stVideo/) 2 | HTML5 video canvas player. Prevents video fullscreen on iPhone/iPad. 3 | 4 | [SEE DEMO](https://tstabla.github.io/stVideo/) 5 | 6 | ## How to use 7 | 8 | Just create div where canvas or video element will be inserted. 9 | Optionally you can add attribute with params. 10 | 11 | ```html 12 |
13 | ``` 14 | 15 | Then create new object. 16 | 17 | ```javascript 18 | var video = new stVideo( '#player' ); 19 | ``` 20 | 21 | Or create new object with params, if you not added them to HTML element. 22 | 23 | ```javascript 24 | var video = new stVideo( '#player', { 25 | "mp4" : "filename.mp4", //recommended 26 | "webm" : "filename.webm", //recommended 27 | "ogg" : "filename.ogg", 28 | "width" : 524, //required 29 | "height": 270, //required 30 | "force" : "", //'video' or 'canvas', 31 | "framesPerSecond": 30, //needed for canvas refresh, default 30 32 | "volume": 1 //default 33 | } ); 34 | ``` 35 | 36 | Look at the table below, and best use .mp4 and .webm video files format. 37 | 38 | |   | .mp4 | .webm | .ogg | 39 | | --- | :---: | :---: | :---: | 40 | | Android | X |   | X | 41 | | iPhone | X |   |   | 42 | | Firefox |   | X | X | 43 | | Chrome |   | X | X | 44 | | Safari | X |   |   | 45 | | IE >= 9 | X |   |   | 46 | | IE Mobile | X |   |   | 47 | 48 | 49 | At the end, you can play video immediately after initialization. 50 | 51 | ```javascript 52 | video.on( 'canplaythrough', function() { 53 | video.play(); 54 | } ); 55 | ``` 56 | 57 | You can attach other events from list http://www.w3.org/TR/html5/embedded-content-0.html#mediaevents but some of them may not work properly with canvas video for ex. "volumechange". 58 | 59 | Examples: 60 | 61 | ```javascript 62 | video.on( 'play', function() { 63 | console.log( 'play' ); 64 | } ); 65 | 66 | video.on( 'pause', function() { 67 | console.log( 'pause' ); 68 | } ); 69 | 70 | video.on( 'end', function() { 71 | console.log( 'end' ); 72 | } ); 73 | ``` 74 | 75 | ## Events 76 | 77 | ```javascript 78 | video.play(); //play video 79 | 80 | video.pause(); //pause video 81 | 82 | video.on( 'name', function(){} ); //for attach event 83 | 84 | video.destroy(); //not working - future function to remove player 85 | ``` 86 | -------------------------------------------------------------------------------- /gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt){ 2 | 3 | require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks); 4 | 5 | grunt.initConfig({ 6 | 7 | pkg: grunt.file.readJSON('package.json'), 8 | 9 | paths: { 10 | 'dist': 'dist', 11 | 'src': 'src', 12 | }, 13 | 14 | copyright: '/*! \n' + 15 | ' * <%= pkg.name %> \n' + 16 | ' * <%= pkg.description %>\n' + 17 | ' * \n' + 18 | ' * Licensed under the MIT license: \n' + 19 | ' * http://www.opensource.org/licenses/mit-license.php \n' + 20 | ' * \n' + 21 | ' * Any and all use of this script must be accompanied by this copyright/license notice in its present form. \n' + 22 | ' * \n' + 23 | ' * Version: <%= pkg.version %>\n' + 24 | ' * Author: <%= pkg.author.name %> <<%= pkg.author.email %>> (<%= pkg.author.url %>)\n' + 25 | ' * Site: <%= pkg.homepage %>/\n' + 26 | ' */\n' + 27 | '', 28 | 29 | jshint: { 30 | src: { 31 | options: { 32 | '-W099': true, 33 | expr: true 34 | }, 35 | src: [ 36 | 'gruntfile.js', 37 | '<%= paths.src %>/js/**/*.js' 38 | ] 39 | } 40 | }, 41 | 42 | concat: { 43 | options: { 44 | separator: ';', 45 | banner: '<%= copyright %>' 46 | }, 47 | dist: { 48 | src: ['<%= paths.src %>/js/stvideo.js'], 49 | dest: '<%= paths.dist %>/js/stvideo.js' 50 | } 51 | }, 52 | 53 | copy : { 54 | files: { 55 | expand: true, 56 | cwd: '<%= paths.src %>', 57 | src: ['**/fonts/**', '**/css/**'], 58 | dest: '<%= paths.dist %>/' 59 | } 60 | }, 61 | 62 | uglify: { 63 | dist: { 64 | options: { 65 | report: 'min', 66 | banner: '<%= copyright %>', 67 | sourceMap: true, 68 | }, 69 | files: [{ 70 | '<%= paths.dist %>/js/stvideo.min.js': ['<%= paths.dist %>/js/stvideo.js'] 71 | }], 72 | } 73 | }, 74 | 75 | watch: { 76 | js: { 77 | files: [ 78 | '<%= paths.src %>/js/**/*.js', 79 | ], 80 | tasks: ['buildjs'] 81 | }, 82 | css: { 83 | files: [ 84 | '<%= paths.src %>/css/**', 85 | ], 86 | tasks: ['copy'] 87 | } 88 | } 89 | }); 90 | 91 | grunt.registerTask('default', [ 92 | 'copy', 'buildjs', 'watch' 93 | ]); 94 | 95 | grunt.registerTask('build', [ 96 | 'copy', 'buildjs' 97 | ]); 98 | 99 | grunt.registerTask('buildjs', [ 100 | 'jshint', 'concat', 'uglify', 101 | ]); 102 | 103 | 104 | }; 105 | -------------------------------------------------------------------------------- /dist/css/stvideo.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'stvideo'; 3 | src: url('../fonts/stvideo.eot?21066397'); 4 | src: url('../fonts/stvideo.eot?21066397#iefix') format('embedded-opentype'), 5 | url('../fonts/stvideo.woff2?21066397') format('woff2'), 6 | url('../fonts/stvideo.woff?21066397') format('woff'), 7 | url('../fonts/stvideo.ttf?21066397') format('truetype'), 8 | url('../fonts/stvideo.svg?21066397#fontello') format('svg'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | 13 | /*volume-off { content: '\e800'; }*/ 14 | /*volume-down { content: '\e801'; }*/ 15 | /*volume { content: '\e802'; }*/ 16 | /*volume-up { content: '\e803'; }*/ 17 | /*pause { content: '\f00e'; }*/ 18 | /*play { content: '\f00f'; }*/ 19 | 20 | 21 | .stvideo-box { 22 | margin: 0 auto; 23 | width: 100%; 24 | max-width: 524px; 25 | position: relative; 26 | } 27 | 28 | .stvideo-box * { 29 | margin: 0; 30 | padding: 0; 31 | } 32 | 33 | .stvideo-box *:before { 34 | font-weight: 400; 35 | -webkit-font-smoothing: antialiased; 36 | -moz-osx-font-smoothing: grayscale; 37 | } 38 | 39 | .stvideo-box__player { 40 | padding-bottom: 56.25%; 41 | width: 100%; 42 | height: 0; 43 | position: relative; 44 | } 45 | 46 | .stvideo-box video, 47 | .stvideo-box canvas { 48 | width: 100%; 49 | height: 100%; 50 | position: absolute; 51 | top: 0; left: 0; 52 | } 53 | 54 | .stvideo-box__play { 55 | cursor: pointer; 56 | margin-top: -5%; 57 | margin-left: -5%; 58 | padding-bottom: 10%; 59 | width: 10%; 60 | height: 0; 61 | position: absolute; 62 | top: 50%; left: 50%; 63 | z-index: 5; 64 | background: rgba(236,240,241,0.95); 65 | border-radius: 100%; 66 | transition: opacity 0.3s linear, visibility 0s linear 0.3s; 67 | } 68 | 69 | .stvideo-box__play:before { 70 | content: '\f00f'; 71 | font-size: 24px; 72 | line-height: 1; 73 | font-family: stvideo; 74 | color: #1bb592; 75 | margin-left: 2px; 76 | position: absolute; 77 | top: 50%; left: 50%; 78 | -ms-transform: translate(-50%, -50%); 79 | transform: translate(-50%, -50%); 80 | transition: color 0.3s linear; 81 | } 82 | 83 | .stvideo-box__play:hover:before { 84 | color: #179d7e; 85 | } 86 | 87 | .stvideo-box--is-playing .stvideo-box__play { 88 | opacity: 0; 89 | visibility: hidden; 90 | } 91 | 92 | .stvideo-box__controls { 93 | padding: 12px 94px 12px 48px; 94 | width: 100%; 95 | position: absolute; 96 | bottom: 0; left: 0; 97 | z-index: 5; 98 | background: #253244; 99 | box-sizing: border-box; 100 | } 101 | 102 | .stvideo-box--has-audio .stvideo-box__controls { 103 | padding-left: 73px; 104 | } 105 | 106 | 107 | .stvideo-box__play-pause { 108 | cursor: pointer; 109 | position: absolute; 110 | top: 10px; left: 12px; 111 | } 112 | 113 | .stvideo-box__play-pause:before { 114 | content: '\f00f'; 115 | font-size: 16px; 116 | line-height: 1; 117 | font-family: stvideo; 118 | color: #1bb592; 119 | } 120 | 121 | .stvideo-box__play-pause:hover:before { 122 | color: #179d7e; 123 | } 124 | 125 | .stvideo-box--is-playing .stvideo-box__play-pause:before { 126 | content: '\f00e'; 127 | } 128 | 129 | .stvideo-box__timeline { 130 | width: 100%; 131 | height: 12px; 132 | position: relative; 133 | background: #ecf0f1; 134 | border-radius: 5px; 135 | } 136 | 137 | .stvideo-box__progress { 138 | width: 0; 139 | height: 100%; 140 | background: #1abc9c; 141 | border-radius: 5px; 142 | transition: width 0.15s linear; 143 | } 144 | 145 | .stvideo-box__handle { 146 | margin: -2px 0 0 -8px; 147 | width: 16px; 148 | height: 16px; 149 | position: absolute; 150 | top: 0; left: 0; 151 | background: #1b9f80; 152 | border-radius: 100%; 153 | } 154 | 155 | .stvideo-box__duration { 156 | font-size: 12px; 157 | line-height: 1; 158 | font-weight: 600; 159 | font-family: Arial, Helvetica, sans-serif; 160 | color: #fff; 161 | -webkit-font-smoothing: antialiased; 162 | -moz-osx-font-smoothing: grayscale; 163 | position: absolute; 164 | top: 12px; right: 8px; 165 | } 166 | 167 | .stvideo-box__volume { 168 | display: none; 169 | cursor: pointer; 170 | position: absolute; 171 | top: 10px; left: 40px; 172 | } 173 | 174 | .stvideo-box__volume:before { 175 | content: '\e802'; 176 | font-size: 16px; 177 | line-height: 1; 178 | font-family: stvideo; 179 | color: rgba(236,240,241,0.95); 180 | } 181 | 182 | .stvideo-box--has-audio .stvideo-box__volume { 183 | display: block; 184 | } 185 | 186 | .stvideo-box--is-muted .stvideo-box__volume:before { 187 | content: '\e800'; 188 | } 189 | -------------------------------------------------------------------------------- /src/css/stvideo.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'stvideo'; 3 | src: url('../fonts/stvideo.eot?21066397'); 4 | src: url('../fonts/stvideo.eot?21066397#iefix') format('embedded-opentype'), 5 | url('../fonts/stvideo.woff2?21066397') format('woff2'), 6 | url('../fonts/stvideo.woff?21066397') format('woff'), 7 | url('../fonts/stvideo.ttf?21066397') format('truetype'), 8 | url('../fonts/stvideo.svg?21066397#fontello') format('svg'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | 13 | /*volume-off { content: '\e800'; }*/ 14 | /*volume-down { content: '\e801'; }*/ 15 | /*volume { content: '\e802'; }*/ 16 | /*volume-up { content: '\e803'; }*/ 17 | /*pause { content: '\f00e'; }*/ 18 | /*play { content: '\f00f'; }*/ 19 | 20 | 21 | .stvideo-box { 22 | margin: 0 auto; 23 | width: 100%; 24 | max-width: 524px; 25 | position: relative; 26 | } 27 | 28 | .stvideo-box * { 29 | margin: 0; 30 | padding: 0; 31 | } 32 | 33 | .stvideo-box *:before { 34 | font-weight: 400; 35 | -webkit-font-smoothing: antialiased; 36 | -moz-osx-font-smoothing: grayscale; 37 | } 38 | 39 | .stvideo-box__player { 40 | padding-bottom: 56.25%; 41 | width: 100%; 42 | height: 0; 43 | position: relative; 44 | } 45 | 46 | .stvideo-box video, 47 | .stvideo-box canvas { 48 | width: 100%; 49 | height: 100%; 50 | position: absolute; 51 | top: 0; left: 0; 52 | } 53 | 54 | .stvideo-box__play { 55 | cursor: pointer; 56 | margin-top: -5%; 57 | margin-left: -5%; 58 | padding-bottom: 10%; 59 | width: 10%; 60 | height: 0; 61 | position: absolute; 62 | top: 50%; left: 50%; 63 | z-index: 5; 64 | background: rgba(236,240,241,0.95); 65 | border-radius: 100%; 66 | transition: opacity 0.3s linear, visibility 0s linear 0.3s; 67 | } 68 | 69 | .stvideo-box__play:before { 70 | content: '\f00f'; 71 | font-size: 24px; 72 | line-height: 1; 73 | font-family: stvideo; 74 | color: #1bb592; 75 | margin-left: 2px; 76 | position: absolute; 77 | top: 50%; left: 50%; 78 | -ms-transform: translate(-50%, -50%); 79 | transform: translate(-50%, -50%); 80 | transition: color 0.3s linear; 81 | } 82 | 83 | .stvideo-box__play:hover:before { 84 | color: #179d7e; 85 | } 86 | 87 | .stvideo-box--is-playing .stvideo-box__play { 88 | opacity: 0; 89 | visibility: hidden; 90 | } 91 | 92 | .stvideo-box__controls { 93 | padding: 12px 94px 12px 48px; 94 | width: 100%; 95 | position: absolute; 96 | bottom: 0; left: 0; 97 | z-index: 5; 98 | background: #253244; 99 | box-sizing: border-box; 100 | } 101 | 102 | .stvideo-box--has-audio .stvideo-box__controls { 103 | padding-left: 73px; 104 | } 105 | 106 | 107 | .stvideo-box__play-pause { 108 | cursor: pointer; 109 | position: absolute; 110 | top: 10px; left: 12px; 111 | } 112 | 113 | .stvideo-box__play-pause:before { 114 | content: '\f00f'; 115 | font-size: 16px; 116 | line-height: 1; 117 | font-family: stvideo; 118 | color: #1bb592; 119 | } 120 | 121 | .stvideo-box__play-pause:hover:before { 122 | color: #179d7e; 123 | } 124 | 125 | .stvideo-box--is-playing .stvideo-box__play-pause:before { 126 | content: '\f00e'; 127 | } 128 | 129 | .stvideo-box__timeline { 130 | width: 100%; 131 | height: 12px; 132 | position: relative; 133 | background: #ecf0f1; 134 | border-radius: 5px; 135 | } 136 | 137 | .stvideo-box__progress { 138 | width: 0; 139 | height: 100%; 140 | background: #1abc9c; 141 | border-radius: 5px; 142 | transition: width 0.15s linear; 143 | } 144 | 145 | .stvideo-box__handle { 146 | margin: -2px 0 0 -8px; 147 | width: 16px; 148 | height: 16px; 149 | position: absolute; 150 | top: 0; left: 0; 151 | background: #1b9f80; 152 | border-radius: 100%; 153 | } 154 | 155 | .stvideo-box__duration { 156 | font-size: 12px; 157 | line-height: 1; 158 | font-weight: 600; 159 | font-family: Arial, Helvetica, sans-serif; 160 | color: #fff; 161 | -webkit-font-smoothing: antialiased; 162 | -moz-osx-font-smoothing: grayscale; 163 | position: absolute; 164 | top: 12px; right: 8px; 165 | } 166 | 167 | .stvideo-box__volume { 168 | display: none; 169 | cursor: pointer; 170 | position: absolute; 171 | top: 10px; left: 40px; 172 | } 173 | 174 | .stvideo-box__volume:before { 175 | content: '\e802'; 176 | font-size: 16px; 177 | line-height: 1; 178 | font-family: stvideo; 179 | color: rgba(236,240,241,0.95); 180 | } 181 | 182 | .stvideo-box--has-audio .stvideo-box__volume { 183 | display: block; 184 | } 185 | 186 | .stvideo-box--is-muted .stvideo-box__volume:before { 187 | content: '\e800'; 188 | } 189 | -------------------------------------------------------------------------------- /dist/js/stvideo.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * stVideo 3 | * HTML5 video canvas player. Prevents video fullscreen on iPhone/iPad. 4 | * 5 | * Licensed under the MIT license: 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Any and all use of this script must be accompanied by this copyright/license notice in its present form. 9 | * 10 | * Version: 0.9.0 11 | * Author: Tomasz Stabla (http://stabla.com) 12 | * Site: https://github.com/tstabla/stVideo/ 13 | */ 14 | 15 | !function(a,b){"function"==typeof define&&define.amd?define([],function(){return b(a)}):"object"==typeof module&&module.exports?module.exports=b(a):a.stVideo=b(a)}("undefined"!=typeof global?global:this.window||this.global,function(a){"use strict";!function(a){for(var b=0,c=["ms","moz","webkit","o"],d=0;d=10&&c.setAttribute("playsinline",""),a=this.supportedVideoFormat(c),!a||this.useCanvas&&!this.settings.mp4||!this.settings[a.ext]?void this.error.badVideoFormat.call(this):(d=document.createElement("source"),d.setAttribute("src",this.settings[a.ext]),d.setAttribute("type",a.type),c.appendChild(d),b=document.createElement("div"),b.classList.add(this.classNames.player),this.useCanvas?(e=document.createElement("canvas"),e.setAttribute("width",this.settings.width),e.setAttribute("height",this.settings.height),f=e.getContext("2d"),f.fillStyle="#ffffff",f.fillRect(0,0,this.settings.width,this.settings.height),f.drawImage(c,0,0,this.settings.width,this.settings.height),this.canvasContext=f,b.appendChild(e)):b.appendChild(c),this.element.appendChild(b),c.load(),this.video=c,this.playerControls(),this.addVideoListeners(),this.addControlsListeners(),void(this.isMobile?window.addEventListener("orientationchange",function(){this.resizeTo&&clearTimeout(this.resizeTo),this.resizeTo=setTimeout(function(){for(g=0;g.01?b.changeState("muted",!1):b.changeState("muted",!0)}),b.eventsVideoCollection.push(a),this.video.addEventListener("error",a=function(a){b.isError=!0,b.error.custom(a)}),b.eventsVideoCollection.push(a)},b.prototype.addControlsListeners=function(a){var b,c=this;this.elPlay.addEventListener("click",b=function(){c.isPlaying?c.pause():c.play()}),c.eventsControlsCollection.push(b),this.elPlayPause.addEventListener("click",b=function(){c.isPlaying?c.pause():c.play()}),c.eventsControlsCollection.push(b),this.useTouch?(this.elHandle.addEventListener("touchstart",b=function(a){a.stopPropagation(),c.timelineSettings.isHandleMoving=!0,c.timelineSettings.touchObj=a.changedTouches[0],c.timelineSettings.posLeft=c.timelineSettings.lastPosLeft,c.timelineSettings.startX=parseInt(c.timelineSettings.touchObj.clientX),c.changeState("handle",!0)},!1),c.eventsControlsCollection.push(b),this.elHandle.addEventListener("touchmove",b=function(a){if(c.timelineSettings.isHandleMoving){a.stopPropagation(),c.timelineSettings.touchObj=a.changedTouches[0];var b=parseInt(c.timelineSettings.touchObj.clientX)-c.timelineSettings.startX;c.moveHandle(b)}},!1),c.eventsControlsCollection.push(b),this.elHandle.addEventListener("touchend",b=function(a){a.preventDefault(),c.timelineSettings.posLeft=c.timelineSettings.lastPosLeft,c.moveHandle(0,!0),c.changeState("handle",!1),c.timelineSettings.isHandleMoving=!1},!1),c.eventsControlsCollection.push(b)):(document.body.addEventListener("mousedown",b=function(a){if(a.preventDefault(),c.timelineSettings.isHandleMoving=!0,c.isContained(c.elHandle,a))c.timelineSettings.touchObj=a,c.timelineSettings.posLeft=c.timelineSettings.lastPosLeft,c.timelineSettings.startX=parseInt(a.clientX),c.timelineSettings.isMouseDown=!0,c.changeState("handle",!0);else if(c.isContained(c.elTimeline,a)){c.timelineSettings.touchObj=a,c.timelineSettings.posLeft=0,c.timelineSettings.startX=parseInt(a.layerX);var b=c.timelineSettings.startX;c.moveHandle(b,!0),c.timelineSettings.isHandleMoving=!1}else c.timelineSettings.isHandleMoving=!1},!1),c.eventsControlsCollection.push(b),document.body.addEventListener("mousemove",b=function(a){if(a.preventDefault(),c.timelineSettings.isMouseDown&&c.timelineSettings.isHandleMoving){c.timelineSettings.touchObj=a;var b=parseInt(c.timelineSettings.touchObj.clientX)-c.timelineSettings.startX;c.moveHandle(b)}},!1),c.eventsControlsCollection.push(b),document.body.addEventListener("mouseup",b=function(a){a.preventDefault(),c.timelineSettings.isMouseDown&&(c.timelineSettings.touchObj=a,c.timelineSettings.posLeft=c.timelineSettings.lastPosLeft,c.timelineSettings.startX=parseInt(c.timelineSettings.touchObj.clientX),c.timelineSettings.isMouseDown=!1,c.moveHandle(0,!0),c.changeState("handle",!1),c.timelineSettings.isHandleMoving=!1)},!1),c.eventsControlsCollection.push(b))},b.prototype.canvasAudio=function(){this.audio=document.createElement("audio"),this.audio.innerHTML=this.video.innerHTML,this.audio.load()},b.prototype.canvasControl=function(b){"play"===b||"play"===b&&this.isEnded?(this.isEnded&&(this.changeState("end",!1),this.video.currentTime=0,this.audio&&(this.audio.currentTime=0),this.lastTime=Date.now()),this.audio&&this.isMuted!==!0&&this.audio.play(),this.changeState("play",!0),this.animationFrame=a.requestAnimationFrame(this.canvasFrameUpdate.bind(this))):"pause"!==b&&"ended"!==b||("ended"===b?this.changeState("end",!0):this.changeState("pause",!0),this.audio&&this.audio.pause(),this.changeState("play",!1),a.cancelAnimationFrame(this.animationFrame))},b.prototype.canvasFrameUpdate=function(){var b=Date.now(),c=(b-(this.lastTime||b))/1e3;(!c||c>=1/this.settings.framesPerSecond)&&(this.video.currentTime=this.video.currentTime+c,this.lastTime=b),this.video.currentTime>=this.video.duration?this.canvasControl("ended"):this.animationFrame=a.requestAnimationFrame(this.canvasFrameUpdate.bind(this))},b.prototype.canvasDrawFrame=function(){this.canvasContext.drawImage(this.video,0,0,this.settings.width,this.settings.height)},b.prototype.progressUpdate=function(a){var b=this.video.currentTime,c=this.video.duration,d=this.timelineSettings;a&&(b=this.video.currentTime=a/d.wrapperWidth*c);var e=(b/c*d.wrapperWidth).toFixed(2);e<0?e=0:e>d.wrapperWidth&&(e=d.wrapperWidth),this.elProgress.style.width=+e+"px",d.isHandleMoving||(this.elHandle.style.left=+e+"px"),this.elDuration.innerText=this.formatTime(b)+" / "+this.formatTime(c)},b.prototype.formatTime=function(a){var b,c;return b=Math.floor(a/60),b=b>=10?b:"0"+b,c=Math.floor(a%60),c=c>=10?c:"0"+c,b+":"+c},b.prototype.moveHandle=function(a,b){var c=this.timelineSettings;if(c.isHandleMoving){var d=(b?c.lastDistance:a)>0?"right":"left",e=c.posLeft+a;e<0?e=0:e>c.wrapperWidth&&(e=c.wrapperWidth),this.elHandle.style.left=e+"px",c.lastPosLeft=e,c.lastDistance=a,c.lastDirection=d,b&&this.progressUpdate(e)}},b.prototype.error={badVideoFormat:function(){this.useCanvas?console.error("Apple devices support only .mp4 format"):console.error("Best use .webm and .mp4 video formats"),this.element.classList.add(this.classNames.error)},checkSettings:function(){console.error("Check all required settings"),this.element.classList.add(this.classNames.error)},custom:function(a){console.error(a),this.element.classList.add(this.classNames.error)}},b.prototype.on=function(a,b){if(!this.isError){var c,d=this;this.video.addEventListener(a,c=function(){b.call(this)}),c.fnName=a,d.eventsUserCollection.push(c)}},b.prototype.eventCallback=function(a){if(this.useCanvas)for(var b in this.eventsUserCollection)this.eventsUserCollection[b].fnName===a&&this.eventsUserCollection[b]()},b.prototype.play=function(){this.isError||(this.lastTime=Date.now(),this.useCanvas?this.canvasControl("play"):this.video.play())},b.prototype.pause=function(){this.isError||this.isPlaying&&(this.useCanvas?this.canvasControl("pause"):this.video.pause())},b.prototype.changeState=function(a,b){var c=this.element.classList;"play"===a&&(this.isPlaying=b,b?(c.add(this.classNames.isPlaying),this.eventCallback("play")):c.remove(this.classNames.isPlaying)),"pause"===a&&(this.isPaused=b,b?(c.add(this.classNames.isPaused),this.eventCallback("pause")):c.remove(this.classNames.isPaused)),"end"===a&&(this.isEnded=b,b?(c.add(this.classNames.isEnded),this.eventCallback("end")):c.remove(this.classNames.isEnded)),"muted"===a&&(this.isMuted=b,b?(c.add(this.classNames.isMuted),this.eventCallback("muted")):c.remove(this.classNames.isMuted)),"handle"===a&&(this.isMuted=b,b?c.add(this.classNames.isHandle):c.remove(this.classNames.isHandle))},b.prototype.destroy=function(){},b}); 16 | //# sourceMappingURL=stvideo.min.js.map -------------------------------------------------------------------------------- /dist/js/stvideo.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["stvideo.js"],"names":["root","factory","define","amd","module","exports","stVideo","global","this","window","lastTime","vendors","x","length","requestAnimationFrame","cancelAnimationFrame","callback","element","currTime","Date","getTime","timeToCall","Math","max","id","setTimeout","clearTimeout","el","settings","iOS","test","navigator","userAgent","iOSv","parseFloat","exec","replace","useCanvas","isMobile","match","useTouch","document","documentElement","ontouchstart","onmsgesturechange","DocumentTouch","querySelector","defaults","force","framesPerSecond","volume","getSettings","mp4","webm","ogg","width","height","classNames","init","error","isPlaying","isPaused","isEnded","isMuted","isHandle","hasAudio","player","poster","play","playPause","controls","timeline","progress","handle","duration","timelineSettings","wrapperWidth","isMouseDown","isHandleMoving","startX","touchObj","posLeft","lastPosLeft","lastDistance","lastDirection","eventsUserCollection","eventsVideoCollection","eventsControlsCollection","initPlayer","isError","checkSettings","prototype","attr","options","key","getAttribute","JSON","parse","hasOwnProperty","isContained","m","ev","e","event","c","type","target","relatedTarget","fromElement","toElement","parentNode","er","format","wrapper","video","videoSource","canvas","canvasContext","itemIndex","self","classList","add","createElement","setAttribute","supportedVideoFormat","ext","badVideoFormat","call","appendChild","getContext","fillStyle","fillRect","drawImage","load","playerControls","addVideoListeners","addControlsListeners","addEventListener","resizeTo","resizeCacheArr","resizeHandler","fn","push","canPlayType","videoAudio","tempEvent","mozHasAudio","Boolean","webkitAudioDecodedByteCount","audioTracks","elControls","elVolume","audio","currentTime","changeState","pause","style","backgroundImage","elPlay","elPlayPause","elTimeline","elProgress","elHandle","elDuration","canvasAudio","canvasDrawFrame","progressUpdate","offsetWidth","custom","controlsBox","stopPropagation","changedTouches","parseInt","clientX","dist","moveHandle","preventDefault","body","layerX","innerHTML","canvasControl","action","now","animationFrame","canvasFrameUpdate","bind","time","elapsed","movedByDistance","current","toFixed","left","innerText","formatTime","seconds","min","sec","floor","touchEnd","opt","direction","newPosition","console","msg","on","name","fnName","eventCallback","k","value","ec","remove","destroy"],"mappings":"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","file":"stvideo.min.js"} -------------------------------------------------------------------------------- /src/js/stvideo.js: -------------------------------------------------------------------------------- 1 | /* global define */ 2 | 3 | ( function( root, factory ) { 4 | if ( typeof define === 'function' && define.amd ) { 5 | define( [], function() { 6 | return factory( root ); 7 | } ); 8 | } else if ( typeof module === 'object' && module.exports ) { 9 | module.exports = factory( root ); 10 | } else { 11 | root.stVideo = factory( root ); 12 | } 13 | } )( typeof global !== 'undefined' ? global : this.window || this.global, function( root ) { 14 | 'use strict'; 15 | 16 | ( function( window ) { 17 | var lastTime = 0; 18 | var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; 19 | 20 | for ( var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x ) { 21 | window.requestAnimationFrame = window[ vendors[ x ] + 'RequestAnimationFrame' ]; 22 | window.cancelAnimationFrame = window[ vendors[ x ] + 'CancelAnimationFrame' ] || window[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; 23 | } 24 | 25 | if ( !window.requestAnimationFrame ) { 26 | window.requestAnimationFrame = function( callback, element ) { 27 | var currTime = new Date().getTime(); 28 | var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); 29 | var id = window.setTimeout( function() { 30 | callback( currTime + timeToCall ); 31 | }, timeToCall ); 32 | lastTime = currTime + timeToCall; 33 | return id; 34 | }; 35 | } 36 | 37 | if ( !window.cancelAnimationFrame ) { 38 | window.cancelAnimationFrame = function( id ) { 39 | clearTimeout( id ); 40 | }; 41 | } 42 | }( root ) ); 43 | 44 | var stVideo = function( el, settings ) { 45 | this.iOS = ( /iPhone|iPad|iPod/i.test( navigator.userAgent ) ); 46 | 47 | this.iOSv = parseFloat( ( '' + ( /CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec( navigator.userAgent ) || [ 0, '' ] )[ 1 ] ).replace( '_', '.' ).replace( '_', '' ) ) || false; 48 | 49 | if ( this.iOS && this.iOSv < 10 ) { 50 | this.useCanvas = true; 51 | } else { 52 | this.useCanvas = false; 53 | } 54 | 55 | this.isMobile = navigator.userAgent.match( /Android|AvantGo|BlackBerry|DoCoMo|Fennec|iPod|iPhone|iPad|J2ME|MIDP|NetFront|Nokia|Opera Mini|Opera Mobi|PalmOS|PalmSource|portalmmm|Plucker|ReqwirelessWeb|SonyEricsson|Symbian|UP\\.Browser|webOS|Windows CE|Windows Phone OS|Xiino/i ); 56 | 57 | this.useTouch = !!( 'ontouchstart' in window ) || !!( 'ontouchstart' in document.documentElement ) || !!window.ontouchstart || !!window.onmsgesturechange || ( window.DocumentTouch && window.document instanceof window.DocumentTouch ); 58 | 59 | if ( typeof el === 'object' ) { 60 | this.element = el; 61 | } else { 62 | this.element = document.querySelector( el ); 63 | } 64 | 65 | this.defaults = { 66 | force : '', // video | canvas 67 | framesPerSecond : 30, 68 | volume : 1 69 | }; 70 | 71 | this.settings = this.getSettings( settings ); 72 | 73 | if ( !( this.settings.mp4 || this.settings.webm || this.settings.ogg ) || 74 | !this.settings.width || !this.settings.height ) { 75 | 76 | this.isError = true; 77 | 78 | this.error.checkSettings(); 79 | 80 | return; 81 | } 82 | 83 | if ( this.settings.force === 'video' ) { 84 | this.useCanvas = false; 85 | } else if ( this.settings.force === 'canvas' ) { 86 | this.useCanvas = true; 87 | } 88 | 89 | this.classNames = { 90 | init : 'stvideo-box', 91 | error : 'stvideo-box--error', 92 | isPlaying : 'stvideo-box--is-playing', 93 | isPaused : 'stvideo-box--is-paused', 94 | isEnded : 'stvideo-box--is-ended', 95 | isMuted : 'stvideo-box--is-muted', 96 | isHandle : 'stvideo-box--is-handle', 97 | hasAudio : 'stvideo-box--has-audio', 98 | player : 'stvideo-box__player', 99 | poster : 'stvideo-box__poster', 100 | play : 'stvideo-box__play', 101 | playPause : 'stvideo-box__play-pause', 102 | controls : 'stvideo-box__controls', 103 | timeline : 'stvideo-box__timeline', 104 | progress : 'stvideo-box__progress', 105 | handle : 'stvideo-box__handle', 106 | duration : 'stvideo-box__duration', 107 | volume : 'stvideo-box__volume', 108 | }; 109 | 110 | this.timelineSettings = { 111 | wrapperWidth : 0, 112 | isMouseDown : false, 113 | isHandleMoving : false, 114 | startX : 0, 115 | touchObj : null, 116 | posLeft : 0, 117 | lastPosLeft : 0, 118 | lastDistance : 0, 119 | lastDirection : '' 120 | }; 121 | 122 | this.eventsUserCollection = []; 123 | this.eventsVideoCollection = []; 124 | this.eventsControlsCollection = []; 125 | 126 | this.initPlayer(); 127 | }; 128 | 129 | stVideo.prototype.getSettings = function( settings ) { 130 | var attr, options, key; 131 | 132 | if ( !settings ) { 133 | attr = this.element.getAttribute( 'data-stvideo' ); 134 | attr = attr.replace( /\'/g, '"' ); 135 | settings = JSON.parse( attr ); 136 | } 137 | 138 | options = this.defaults; 139 | 140 | for ( key in settings ) { 141 | if ( settings.hasOwnProperty( key ) ) { 142 | options[ key ] = settings[ key ]; 143 | } 144 | } 145 | 146 | return options; 147 | }; 148 | 149 | stVideo.prototype.isContained = function( m, ev ) { 150 | var e = ev || window.event; 151 | 152 | var c = /(click)|(mousedown)|(mouseup)/i.test( e.type ) ? e.target : ( e.relatedTarget || ( ( e.type == 'mouseover' ) ? e.fromElement : e.toElement ) ); 153 | 154 | while ( c && c != m ) { 155 | try { 156 | c = c.parentNode; 157 | } catch ( er ) { 158 | c = m; 159 | } 160 | } 161 | 162 | if ( c == m ) { 163 | return true; 164 | } else { 165 | return false; 166 | } 167 | }; 168 | 169 | stVideo.prototype.initPlayer = function() { 170 | var self = this, format, wrapper, video, videoSource, type, canvas, canvasContext, itemIndex; 171 | 172 | this.element.classList.add( this.classNames.init ); 173 | 174 | video = document.createElement( 'video' ); 175 | video.setAttribute( 'width', this.settings.width ); 176 | video.setAttribute( 'height', this.settings.height ); 177 | 178 | if ( this.iOS && this.iOSv >= 10 ) { 179 | video.setAttribute( 'playsinline', '' ); 180 | } 181 | 182 | format = this.supportedVideoFormat( video ); 183 | 184 | if ( !format || ( this.useCanvas && !this.settings.mp4 ) || !this.settings[ format.ext ] ) { 185 | this.error.badVideoFormat.call( this ); 186 | 187 | return; 188 | } 189 | 190 | videoSource = document.createElement( 'source' ); 191 | videoSource.setAttribute( 'src', this.settings[ format.ext ] ); 192 | videoSource.setAttribute( 'type', format.type ); 193 | 194 | video.appendChild( videoSource ); 195 | 196 | wrapper = document.createElement( 'div' ); 197 | wrapper.classList.add( this.classNames.player ); 198 | 199 | if ( this.useCanvas ) { 200 | canvas = document.createElement( 'canvas' ); 201 | canvas.setAttribute( 'width', this.settings.width ); 202 | canvas.setAttribute( 'height', this.settings.height ); 203 | 204 | canvasContext = canvas.getContext( '2d' ); 205 | 206 | canvasContext.fillStyle = '#ffffff'; 207 | canvasContext.fillRect( 0, 0, this.settings.width, this.settings.height ); 208 | 209 | canvasContext.drawImage( video, 0, 0, this.settings.width, this.settings.height ); 210 | 211 | this.canvasContext = canvasContext; 212 | 213 | wrapper.appendChild( canvas ); 214 | } else { 215 | wrapper.appendChild( video ); 216 | } 217 | 218 | this.element.appendChild( wrapper ); 219 | 220 | video.load(); 221 | 222 | this.video = video; 223 | 224 | this.playerControls(); 225 | this.addVideoListeners(); 226 | this.addControlsListeners(); 227 | 228 | if ( this.isMobile ) { 229 | window.addEventListener( 'orientationchange', function() { 230 | if ( this.resizeTo ) { 231 | clearTimeout( this.resizeTo ); 232 | } 233 | 234 | this.resizeTo = setTimeout( function() { 235 | for ( itemIndex = 0; itemIndex < self.resizeCacheArr.length; itemIndex++ ) { 236 | self.resizeCacheArr[ itemIndex ](); 237 | } 238 | }, 200 ); 239 | }, false ); 240 | } else { 241 | window.addEventListener( 'resize', function() { 242 | if ( this.resizeTo ) { 243 | clearTimeout( this.resizeTo ); 244 | } 245 | 246 | this.resizeTo = setTimeout( function() { 247 | for ( itemIndex = 0; itemIndex < self.resizeCacheArr.length; itemIndex++ ) { 248 | self.resizeCacheArr[ itemIndex ](); 249 | } 250 | }, 200 ); 251 | } ); 252 | } 253 | }; 254 | 255 | stVideo.prototype.resizeHandler = function( fn ) { 256 | this.resizeCacheArr = this.resizeCacheArr || []; 257 | 258 | fn(); 259 | 260 | this.resizeCacheArr.push( fn ); 261 | }; 262 | 263 | stVideo.prototype.supportedVideoFormat = function( video ) { 264 | var options = {}; 265 | 266 | if ( video.canPlayType( 'video/webm' ) === 'probably' || video.canPlayType( 'video/webm' ) === 'maybe' ) { 267 | options.ext = 'webm'; 268 | options.type = 'video/webm; codecs="vp8, vorbis"'; 269 | } else if ( video.canPlayType( 'video/mp4' ) === 'probably' || video.canPlayType( 'video/mp4' ) === 'maybe' ) { 270 | options.ext = 'mp4'; 271 | options.type = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'; 272 | } else if ( video.canPlayType( 'video/ogg' ) === 'probably' || video.canPlayType( 'video/ogg' ) === 'maybe' ) { 273 | options.ext = 'ogg'; 274 | options.type = 'video/ogg; codecs="theora, vorbis"'; 275 | } 276 | 277 | return options; 278 | }; 279 | 280 | stVideo.prototype.videoAudio = function( video ) { 281 | var self = this, tempEvent, volume; 282 | 283 | if ( video.mozHasAudio || Boolean( video.webkitAudioDecodedByteCount ) || Boolean( video.audioTracks && video.audioTracks.length ) ) { 284 | this.hasAudio = true; 285 | 286 | this.element.classList.add( this.classNames.hasAudio ); 287 | 288 | volume = document.createElement( 'div' ); 289 | volume.classList.add( this.classNames.volume ); 290 | 291 | this.elControls.appendChild( volume ); 292 | 293 | this.elVolume = volume; 294 | 295 | this.elVolume.addEventListener( 'click', tempEvent = function() { 296 | if ( self.isMuted ) { 297 | self.video.volume = self.settings.volume; 298 | 299 | if ( self.audio ) { 300 | self.audio.volume = self.settings.volume; 301 | 302 | self.audio.currentTime = self.video.currentTime; 303 | 304 | if ( self.isPlaying ) { 305 | self.audio.play(); 306 | } 307 | 308 | if ( self.iOS ) { 309 | self.changeState( 'muted', false ); 310 | } 311 | } 312 | } else { 313 | self.video.volume = 0.01; 314 | 315 | if ( self.audio ) { 316 | self.audio.volume = 0.01; // hmm doesn't work on iPhone 317 | self.audio.pause(); 318 | 319 | if ( self.iOS ) { 320 | self.changeState( 'muted', true ); 321 | } 322 | } 323 | } 324 | } ); 325 | this.eventsControlsCollection.push( tempEvent ); 326 | } else { 327 | this.hasAudio = false; 328 | } 329 | 330 | return this.hasAudio; 331 | }; 332 | 333 | stVideo.prototype.playerControls = function() { 334 | var self = this, poster, controls, timeline, progress, handle, playPause, play, duration; 335 | 336 | if ( this.settings.poster ) { 337 | poster = document.createElement( 'div' ); 338 | poster.classList.add( this.classNames.poster ); 339 | poster.style.backgroundImage = 'url(' + this.settings.poster + ')'; 340 | 341 | this.element.appendChild( poster ); 342 | } 343 | 344 | play = document.createElement( 'div' ); 345 | play.classList.add( this.classNames.play ); 346 | 347 | controls = document.createElement( 'div' ); 348 | controls.classList.add( this.classNames.controls ); 349 | 350 | playPause = document.createElement( 'div' ); 351 | playPause.classList.add( this.classNames.playPause ); 352 | 353 | timeline = document.createElement( 'div' ); 354 | timeline.classList.add( this.classNames.timeline ); 355 | 356 | progress = document.createElement( 'div' ); 357 | progress.classList.add( this.classNames.progress ); 358 | 359 | handle = document.createElement( 'div' ); 360 | handle.classList.add( this.classNames.handle ); 361 | 362 | duration = document.createElement( 'div' ); 363 | duration.classList.add( this.classNames.duration ); 364 | 365 | timeline.appendChild( progress ); 366 | timeline.appendChild( handle ); 367 | controls.appendChild( timeline ); 368 | controls.appendChild( playPause ); 369 | controls.appendChild( duration ); 370 | 371 | this.element.appendChild( controls ); 372 | this.element.appendChild( play ); 373 | 374 | this.elControls = controls; 375 | this.elPlay = play; 376 | this.elPlayPause = playPause; 377 | this.elTimeline = timeline; 378 | this.elProgress = progress; 379 | this.elHandle = handle; 380 | this.elDuration = duration; 381 | }; 382 | 383 | stVideo.prototype.addVideoListeners = function() { 384 | var self = this, tempEvent; 385 | 386 | this.video.addEventListener( 'loadedmetadata', tempEvent = function() { 387 | var audio = self.videoAudio( this ); 388 | 389 | if ( self.useCanvas && audio ) { 390 | self.canvasAudio(); 391 | } 392 | } ); 393 | self.eventsVideoCollection.push( tempEvent ); 394 | 395 | this.video.addEventListener( 'canplaythrough', tempEvent = function() { 396 | if ( self.useCanvas ) { 397 | self.canvasDrawFrame(); 398 | } 399 | 400 | self.progressUpdate(); 401 | 402 | setTimeout( function() { 403 | self.resizeHandler( function() { 404 | self.timelineSettings.wrapperWidth = self.elTimeline.offsetWidth; 405 | } ); 406 | }, 100 ); 407 | } ); 408 | self.eventsVideoCollection.push( tempEvent ); 409 | 410 | if ( !self.useCanvas ) { 411 | this.video.addEventListener( 'play', tempEvent = function() { 412 | self.changeState( 'play', true ); 413 | self.changeState( 'end', false ); 414 | } ); 415 | self.eventsVideoCollection.push( tempEvent ); 416 | 417 | this.video.addEventListener( 'pause', tempEvent = function() { 418 | self.changeState( 'pause', true ); 419 | self.changeState( 'play', false ); 420 | } ); 421 | self.eventsVideoCollection.push( tempEvent ); 422 | 423 | this.video.addEventListener( 'ended', tempEvent = function() { 424 | self.changeState( 'end', true ); 425 | self.changeState( 'play', false ); 426 | } ); 427 | self.eventsVideoCollection.push( tempEvent ); 428 | } 429 | 430 | this.video.addEventListener( 'timeupdate', tempEvent = function() { 431 | if ( self.useCanvas ) { 432 | self.canvasDrawFrame(); 433 | } 434 | 435 | self.progressUpdate(); 436 | } ); 437 | self.eventsVideoCollection.push( tempEvent ); 438 | 439 | this.video.addEventListener( 'volumechange', tempEvent = function() { 440 | if ( this.volume > 0.01 ) { 441 | self.changeState( 'muted', false ); 442 | } else { 443 | self.changeState( 'muted', true ); 444 | } 445 | } ); 446 | self.eventsVideoCollection.push( tempEvent ); 447 | 448 | this.video.addEventListener( 'error', tempEvent = function( ev ) { 449 | self.isError = true; 450 | 451 | self.error.custom( ev ); 452 | } ); 453 | self.eventsVideoCollection.push( tempEvent ); 454 | }; 455 | 456 | stVideo.prototype.addControlsListeners = function( controlsBox ) { 457 | var self = this, tempEvent; 458 | 459 | this.elPlay.addEventListener( 'click', tempEvent = function() { 460 | if ( !self.isPlaying ) { 461 | self.play(); 462 | } else { 463 | self.pause(); 464 | } 465 | } ); 466 | self.eventsControlsCollection.push( tempEvent ); 467 | 468 | this.elPlayPause.addEventListener( 'click', tempEvent = function() { 469 | if ( !self.isPlaying ) { 470 | self.play(); 471 | } else { 472 | self.pause(); 473 | } 474 | } ); 475 | self.eventsControlsCollection.push( tempEvent ); 476 | 477 | if ( !this.useTouch ) { 478 | document.body.addEventListener( 'mousedown', tempEvent = function( e ) { 479 | e.preventDefault(); 480 | 481 | self.timelineSettings.isHandleMoving = true; 482 | 483 | if ( self.isContained( self.elHandle, e ) ) { 484 | self.timelineSettings.touchObj = e; 485 | self.timelineSettings.posLeft = self.timelineSettings.lastPosLeft; 486 | self.timelineSettings.startX = parseInt( e.clientX ); 487 | 488 | self.timelineSettings.isMouseDown = true; 489 | 490 | self.changeState( 'handle', true ); 491 | } else if ( self.isContained( self.elTimeline, e ) ) { 492 | self.timelineSettings.touchObj = e; 493 | self.timelineSettings.posLeft = 0; 494 | self.timelineSettings.startX = parseInt( e.layerX ); 495 | 496 | var dist = self.timelineSettings.startX; 497 | 498 | self.moveHandle( dist, true ); 499 | 500 | self.timelineSettings.isHandleMoving = false; 501 | } else { 502 | self.timelineSettings.isHandleMoving = false; 503 | } 504 | }, false ); 505 | self.eventsControlsCollection.push( tempEvent ); 506 | 507 | document.body.addEventListener( 'mousemove', tempEvent = function( e ) { 508 | e.preventDefault(); 509 | 510 | if ( self.timelineSettings.isMouseDown && self.timelineSettings.isHandleMoving ) { 511 | self.timelineSettings.touchObj = e; 512 | 513 | var dist = parseInt( self.timelineSettings.touchObj.clientX ) - self.timelineSettings.startX; 514 | 515 | self.moveHandle( dist ); 516 | } 517 | }, false ); 518 | self.eventsControlsCollection.push( tempEvent ); 519 | 520 | document.body.addEventListener( 'mouseup', tempEvent = function( e ) { 521 | e.preventDefault(); 522 | 523 | if ( self.timelineSettings.isMouseDown ) { 524 | self.timelineSettings.touchObj = e; 525 | self.timelineSettings.posLeft = self.timelineSettings.lastPosLeft; 526 | self.timelineSettings.startX = parseInt( self.timelineSettings.touchObj.clientX ); 527 | 528 | self.timelineSettings.isMouseDown = false; 529 | 530 | self.moveHandle( 0, true ); 531 | 532 | self.changeState( 'handle', false ); 533 | 534 | self.timelineSettings.isHandleMoving = false; 535 | } 536 | }, false ); 537 | self.eventsControlsCollection.push( tempEvent ); 538 | 539 | } else { 540 | this.elHandle.addEventListener( 'touchstart', tempEvent = function( e ) { 541 | // e.preventDefault(); 542 | e.stopPropagation(); 543 | 544 | self.timelineSettings.isHandleMoving = true; 545 | 546 | self.timelineSettings.touchObj = e.changedTouches[ 0 ]; 547 | self.timelineSettings.posLeft = self.timelineSettings.lastPosLeft; 548 | self.timelineSettings.startX = parseInt( self.timelineSettings.touchObj.clientX ); 549 | 550 | self.changeState( 'handle', true ); 551 | }, false ); 552 | self.eventsControlsCollection.push( tempEvent ); 553 | 554 | this.elHandle.addEventListener( 'touchmove', tempEvent = function( e ) { 555 | 556 | if ( self.timelineSettings.isHandleMoving ) { 557 | // e.preventDefault(); 558 | e.stopPropagation(); 559 | 560 | self.timelineSettings.touchObj = e.changedTouches[ 0 ]; 561 | 562 | var dist = parseInt( self.timelineSettings.touchObj.clientX ) - self.timelineSettings.startX; 563 | 564 | self.moveHandle( dist ); 565 | } 566 | }, false ); 567 | self.eventsControlsCollection.push( tempEvent ); 568 | 569 | this.elHandle.addEventListener( 'touchend', tempEvent = function( e ) { 570 | e.preventDefault(); 571 | 572 | self.timelineSettings.posLeft = self.timelineSettings.lastPosLeft; 573 | 574 | self.moveHandle( 0, true ); 575 | 576 | self.changeState( 'handle', false ); 577 | 578 | self.timelineSettings.isHandleMoving = false; 579 | }, false ); 580 | self.eventsControlsCollection.push( tempEvent ); 581 | } 582 | }; 583 | 584 | stVideo.prototype.canvasAudio = function() { 585 | this.audio = document.createElement( 'audio' ); 586 | 587 | this.audio.innerHTML = this.video.innerHTML; 588 | 589 | this.audio.load(); 590 | }; 591 | 592 | stVideo.prototype.canvasControl = function( action ) { 593 | if ( action === 'play' || ( action === 'play' && this.isEnded ) ) { 594 | if ( this.isEnded ) { 595 | this.changeState( 'end', false ); 596 | 597 | this.video.currentTime = 0; 598 | 599 | if ( this.audio ) { 600 | this.audio.currentTime = 0; 601 | } 602 | 603 | this.lastTime = Date.now(); 604 | } 605 | 606 | if ( this.audio && this.isMuted !== true ) { 607 | this.audio.play(); 608 | } 609 | 610 | this.changeState( 'play', true ); 611 | 612 | this.animationFrame = root.requestAnimationFrame( this.canvasFrameUpdate.bind( this ) ); 613 | 614 | } else if ( action === 'pause' || action === 'ended' ) { 615 | if ( action === 'ended' ) { 616 | this.changeState( 'end', true ); 617 | } else { 618 | this.changeState( 'pause', true ); 619 | } 620 | 621 | if ( this.audio ) { 622 | this.audio.pause(); 623 | } 624 | 625 | this.changeState( 'play', false ); 626 | 627 | root.cancelAnimationFrame( this.animationFrame ); 628 | } 629 | }; 630 | 631 | stVideo.prototype.canvasFrameUpdate = function() { 632 | var time = Date.now(), 633 | elapsed = ( time - ( this.lastTime || time ) ) / 1000; 634 | 635 | if ( !elapsed || elapsed >= 1 / this.settings.framesPerSecond ) { 636 | this.video.currentTime = this.video.currentTime + elapsed; 637 | 638 | /* if(this.audio && Math.abs(this.audio.currentTime - this.video.currentTime) > 0.3){ 639 | this.audio.pause(); 640 | this.audio.currentTime = this.video.currentTime; 641 | this.audio.play(); 642 | } */ 643 | 644 | this.lastTime = time; 645 | } 646 | 647 | if ( this.video.currentTime >= this.video.duration ) { 648 | this.canvasControl( 'ended' ); 649 | } else { 650 | this.animationFrame = root.requestAnimationFrame( this.canvasFrameUpdate.bind( this ) ); 651 | } 652 | }; 653 | 654 | stVideo.prototype.canvasDrawFrame = function() { 655 | this.canvasContext.drawImage( this.video, 0, 0, this.settings.width, this.settings.height ); 656 | }; 657 | 658 | stVideo.prototype.progressUpdate = function( movedByDistance ) { 659 | var current = this.video.currentTime, 660 | duration = this.video.duration, 661 | timeline = this.timelineSettings; 662 | 663 | if ( movedByDistance ) { 664 | current = this.video.currentTime = ( movedByDistance / timeline.wrapperWidth ) * duration; 665 | } 666 | 667 | var progress = ( current / duration * timeline.wrapperWidth ).toFixed( 2 ); 668 | 669 | if ( progress < 0 ) { 670 | progress = 0; 671 | } else if ( progress > timeline.wrapperWidth ) { 672 | progress = timeline.wrapperWidth; 673 | } 674 | 675 | this.elProgress.style.width = +progress + 'px'; 676 | 677 | if ( !timeline.isHandleMoving ) { 678 | this.elHandle.style.left = +progress + 'px'; 679 | } 680 | 681 | this.elDuration.innerText = this.formatTime( current ) + ' / ' + this.formatTime( duration ); 682 | }; 683 | 684 | stVideo.prototype.formatTime = function( seconds ) { 685 | var min, sec; 686 | 687 | min = Math.floor( seconds / 60 ); 688 | min = ( min >= 10 ) ? min : '0' + min; 689 | sec = Math.floor( seconds % 60 ); 690 | sec = ( sec >= 10 ) ? sec : '0' + sec; 691 | 692 | return min + ':' + sec; 693 | }; 694 | 695 | stVideo.prototype.moveHandle = function( movedByDistance, touchEnd ) { 696 | var opt = this.timelineSettings; 697 | 698 | if ( !opt.isHandleMoving ) { 699 | return; 700 | } 701 | 702 | var direction = ( ( touchEnd ? opt.lastDistance : movedByDistance ) > 0 ) ? 'right' : 'left'; 703 | 704 | var newPosition = opt.posLeft + movedByDistance; 705 | 706 | if ( newPosition < 0 ) { 707 | newPosition = 0; 708 | } else if ( newPosition > opt.wrapperWidth ) { 709 | newPosition = opt.wrapperWidth; 710 | } 711 | 712 | this.elHandle.style.left = newPosition + 'px'; 713 | 714 | opt.lastPosLeft = newPosition; 715 | opt.lastDistance = movedByDistance; 716 | opt.lastDirection = direction; 717 | 718 | if ( touchEnd ) { 719 | this.progressUpdate( newPosition ); 720 | } 721 | }; 722 | 723 | stVideo.prototype.error = { 724 | badVideoFormat: function() { 725 | if ( this.useCanvas ) { 726 | console.error( 'Apple devices support only .mp4 format' ); 727 | } else { 728 | console.error( 'Best use .webm and .mp4 video formats' ); 729 | } 730 | 731 | this.element.classList.add( this.classNames.error ); 732 | }, 733 | checkSettings: function() { 734 | console.error( 'Check all required settings' ); 735 | 736 | this.element.classList.add( this.classNames.error ); 737 | }, 738 | custom: function( msg ) { 739 | console.error( msg ); 740 | 741 | this.element.classList.add( this.classNames.error ); 742 | } 743 | }; 744 | 745 | stVideo.prototype.on = function( name, callback ) { 746 | if ( this.isError ) { 747 | return; 748 | } 749 | 750 | var self = this, tempEvent; 751 | 752 | // this.allowedEvents = ['canplay', 'canplaythrough', 'play', 'playing', 'pause', 'ended', 'abort', 'error', 'timeupdate']; 753 | 754 | // if(this.allowedEvents.indexOf(name) == -1) return; 755 | 756 | this.video.addEventListener( name, tempEvent = function() { 757 | callback.call( this ); 758 | } ); 759 | 760 | tempEvent.fnName = name; 761 | 762 | self.eventsUserCollection.push( tempEvent ); 763 | }; 764 | 765 | stVideo.prototype.eventCallback = function( name ) { 766 | if ( this.useCanvas ) { 767 | for ( var k in this.eventsUserCollection ) { 768 | if ( this.eventsUserCollection[ k ].fnName === name ) { 769 | this.eventsUserCollection[ k ](); 770 | } 771 | } 772 | } 773 | }; 774 | 775 | stVideo.prototype.play = function() { 776 | if ( this.isError ) { 777 | return; 778 | } 779 | 780 | this.lastTime = Date.now(); 781 | 782 | if ( this.useCanvas ) { 783 | this.canvasControl( 'play' ); 784 | } else { 785 | this.video.play(); 786 | } 787 | }; 788 | 789 | stVideo.prototype.pause = function() { 790 | if ( this.isError ) { 791 | return; 792 | } 793 | 794 | if ( this.isPlaying ) { 795 | if ( this.useCanvas ) { 796 | this.canvasControl( 'pause' ); 797 | } else { 798 | this.video.pause(); 799 | } 800 | } 801 | }; 802 | 803 | stVideo.prototype.changeState = function( action, value ) { 804 | var ec = this.element.classList; 805 | 806 | if ( action === 'play' ) { 807 | this.isPlaying = value; 808 | 809 | if ( value ) { 810 | ec.add( this.classNames.isPlaying ); 811 | 812 | this.eventCallback( 'play' ); 813 | } else { 814 | ec.remove( this.classNames.isPlaying ); 815 | } 816 | } 817 | 818 | if ( action === 'pause' ) { 819 | this.isPaused = value; 820 | 821 | if ( value ) { 822 | ec.add( this.classNames.isPaused ); 823 | 824 | this.eventCallback( 'pause' ); 825 | } else { 826 | ec.remove( this.classNames.isPaused ); 827 | } 828 | } 829 | 830 | if ( action === 'end' ) { 831 | this.isEnded = value; 832 | 833 | if ( value ) { 834 | ec.add( this.classNames.isEnded ); 835 | 836 | this.eventCallback( 'end' ); 837 | } else { 838 | ec.remove( this.classNames.isEnded ); 839 | } 840 | } 841 | 842 | if ( action === 'muted' ) { 843 | this.isMuted = value; 844 | 845 | if ( value ) { 846 | ec.add( this.classNames.isMuted ); 847 | 848 | this.eventCallback( 'muted' ); 849 | } else { 850 | ec.remove( this.classNames.isMuted ); 851 | } 852 | } 853 | 854 | if ( action === 'handle' ) { 855 | this.isMuted = value; 856 | 857 | if ( value ) { 858 | ec.add( this.classNames.isHandle ); 859 | } else { 860 | ec.remove( this.classNames.isHandle ); 861 | } 862 | } 863 | }; 864 | 865 | stVideo.prototype.destroy = function() { 866 | 867 | }; 868 | 869 | return stVideo; 870 | } ); 871 | -------------------------------------------------------------------------------- /dist/js/stvideo.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * stVideo 3 | * HTML5 video canvas player. Prevents video fullscreen on iPhone/iPad. 4 | * 5 | * Licensed under the MIT license: 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Any and all use of this script must be accompanied by this copyright/license notice in its present form. 9 | * 10 | * Version: 0.9.0 11 | * Author: Tomasz Stabla (http://stabla.com) 12 | * Site: https://github.com/tstabla/stVideo/ 13 | */ 14 | /* global define */ 15 | 16 | ( function( root, factory ) { 17 | if ( typeof define === 'function' && define.amd ) { 18 | define( [], function() { 19 | return factory( root ); 20 | } ); 21 | } else if ( typeof module === 'object' && module.exports ) { 22 | module.exports = factory( root ); 23 | } else { 24 | root.stVideo = factory( root ); 25 | } 26 | } )( typeof global !== 'undefined' ? global : this.window || this.global, function( root ) { 27 | 'use strict'; 28 | 29 | ( function( window ) { 30 | var lastTime = 0; 31 | var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; 32 | 33 | for ( var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x ) { 34 | window.requestAnimationFrame = window[ vendors[ x ] + 'RequestAnimationFrame' ]; 35 | window.cancelAnimationFrame = window[ vendors[ x ] + 'CancelAnimationFrame' ] || window[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; 36 | } 37 | 38 | if ( !window.requestAnimationFrame ) { 39 | window.requestAnimationFrame = function( callback, element ) { 40 | var currTime = new Date().getTime(); 41 | var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); 42 | var id = window.setTimeout( function() { 43 | callback( currTime + timeToCall ); 44 | }, timeToCall ); 45 | lastTime = currTime + timeToCall; 46 | return id; 47 | }; 48 | } 49 | 50 | if ( !window.cancelAnimationFrame ) { 51 | window.cancelAnimationFrame = function( id ) { 52 | clearTimeout( id ); 53 | }; 54 | } 55 | }( root ) ); 56 | 57 | var stVideo = function( el, settings ) { 58 | this.iOS = ( /iPhone|iPad|iPod/i.test( navigator.userAgent ) ); 59 | 60 | this.iOSv = parseFloat( ( '' + ( /CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec( navigator.userAgent ) || [ 0, '' ] )[ 1 ] ).replace( '_', '.' ).replace( '_', '' ) ) || false; 61 | 62 | if ( this.iOS && this.iOSv < 10 ) { 63 | this.useCanvas = true; 64 | } else { 65 | this.useCanvas = false; 66 | } 67 | 68 | this.isMobile = navigator.userAgent.match( /Android|AvantGo|BlackBerry|DoCoMo|Fennec|iPod|iPhone|iPad|J2ME|MIDP|NetFront|Nokia|Opera Mini|Opera Mobi|PalmOS|PalmSource|portalmmm|Plucker|ReqwirelessWeb|SonyEricsson|Symbian|UP\\.Browser|webOS|Windows CE|Windows Phone OS|Xiino/i ); 69 | 70 | this.useTouch = !!( 'ontouchstart' in window ) || !!( 'ontouchstart' in document.documentElement ) || !!window.ontouchstart || !!window.onmsgesturechange || ( window.DocumentTouch && window.document instanceof window.DocumentTouch ); 71 | 72 | if ( typeof el === 'object' ) { 73 | this.element = el; 74 | } else { 75 | this.element = document.querySelector( el ); 76 | } 77 | 78 | this.defaults = { 79 | force : '', // video | canvas 80 | framesPerSecond : 30, 81 | volume : 1 82 | }; 83 | 84 | this.settings = this.getSettings( settings ); 85 | 86 | if ( !( this.settings.mp4 || this.settings.webm || this.settings.ogg ) || 87 | !this.settings.width || !this.settings.height ) { 88 | 89 | this.isError = true; 90 | 91 | this.error.checkSettings(); 92 | 93 | return; 94 | } 95 | 96 | if ( this.settings.force === 'video' ) { 97 | this.useCanvas = false; 98 | } else if ( this.settings.force === 'canvas' ) { 99 | this.useCanvas = true; 100 | } 101 | 102 | this.classNames = { 103 | init : 'stvideo-box', 104 | error : 'stvideo-box--error', 105 | isPlaying : 'stvideo-box--is-playing', 106 | isPaused : 'stvideo-box--is-paused', 107 | isEnded : 'stvideo-box--is-ended', 108 | isMuted : 'stvideo-box--is-muted', 109 | isHandle : 'stvideo-box--is-handle', 110 | hasAudio : 'stvideo-box--has-audio', 111 | player : 'stvideo-box__player', 112 | poster : 'stvideo-box__poster', 113 | play : 'stvideo-box__play', 114 | playPause : 'stvideo-box__play-pause', 115 | controls : 'stvideo-box__controls', 116 | timeline : 'stvideo-box__timeline', 117 | progress : 'stvideo-box__progress', 118 | handle : 'stvideo-box__handle', 119 | duration : 'stvideo-box__duration', 120 | volume : 'stvideo-box__volume', 121 | }; 122 | 123 | this.timelineSettings = { 124 | wrapperWidth : 0, 125 | isMouseDown : false, 126 | isHandleMoving : false, 127 | startX : 0, 128 | touchObj : null, 129 | posLeft : 0, 130 | lastPosLeft : 0, 131 | lastDistance : 0, 132 | lastDirection : '' 133 | }; 134 | 135 | this.eventsUserCollection = []; 136 | this.eventsVideoCollection = []; 137 | this.eventsControlsCollection = []; 138 | 139 | this.initPlayer(); 140 | }; 141 | 142 | stVideo.prototype.getSettings = function( settings ) { 143 | var attr, options, key; 144 | 145 | if ( !settings ) { 146 | attr = this.element.getAttribute( 'data-stvideo' ); 147 | attr = attr.replace( /\'/g, '"' ); 148 | settings = JSON.parse( attr ); 149 | } 150 | 151 | options = this.defaults; 152 | 153 | for ( key in settings ) { 154 | if ( settings.hasOwnProperty( key ) ) { 155 | options[ key ] = settings[ key ]; 156 | } 157 | } 158 | 159 | return options; 160 | }; 161 | 162 | stVideo.prototype.isContained = function( m, ev ) { 163 | var e = ev || window.event; 164 | 165 | var c = /(click)|(mousedown)|(mouseup)/i.test( e.type ) ? e.target : ( e.relatedTarget || ( ( e.type == 'mouseover' ) ? e.fromElement : e.toElement ) ); 166 | 167 | while ( c && c != m ) { 168 | try { 169 | c = c.parentNode; 170 | } catch ( er ) { 171 | c = m; 172 | } 173 | } 174 | 175 | if ( c == m ) { 176 | return true; 177 | } else { 178 | return false; 179 | } 180 | }; 181 | 182 | stVideo.prototype.initPlayer = function() { 183 | var self = this, format, wrapper, video, videoSource, type, canvas, canvasContext, itemIndex; 184 | 185 | this.element.classList.add( this.classNames.init ); 186 | 187 | video = document.createElement( 'video' ); 188 | video.setAttribute( 'width', this.settings.width ); 189 | video.setAttribute( 'height', this.settings.height ); 190 | 191 | if ( this.iOS && this.iOSv >= 10 ) { 192 | video.setAttribute( 'playsinline', '' ); 193 | } 194 | 195 | format = this.supportedVideoFormat( video ); 196 | 197 | if ( !format || ( this.useCanvas && !this.settings.mp4 ) || !this.settings[ format.ext ] ) { 198 | this.error.badVideoFormat.call( this ); 199 | 200 | return; 201 | } 202 | 203 | videoSource = document.createElement( 'source' ); 204 | videoSource.setAttribute( 'src', this.settings[ format.ext ] ); 205 | videoSource.setAttribute( 'type', format.type ); 206 | 207 | video.appendChild( videoSource ); 208 | 209 | wrapper = document.createElement( 'div' ); 210 | wrapper.classList.add( this.classNames.player ); 211 | 212 | if ( this.useCanvas ) { 213 | canvas = document.createElement( 'canvas' ); 214 | canvas.setAttribute( 'width', this.settings.width ); 215 | canvas.setAttribute( 'height', this.settings.height ); 216 | 217 | canvasContext = canvas.getContext( '2d' ); 218 | 219 | canvasContext.fillStyle = '#ffffff'; 220 | canvasContext.fillRect( 0, 0, this.settings.width, this.settings.height ); 221 | 222 | canvasContext.drawImage( video, 0, 0, this.settings.width, this.settings.height ); 223 | 224 | this.canvasContext = canvasContext; 225 | 226 | wrapper.appendChild( canvas ); 227 | } else { 228 | wrapper.appendChild( video ); 229 | } 230 | 231 | this.element.appendChild( wrapper ); 232 | 233 | video.load(); 234 | 235 | this.video = video; 236 | 237 | this.playerControls(); 238 | this.addVideoListeners(); 239 | this.addControlsListeners(); 240 | 241 | if ( this.isMobile ) { 242 | window.addEventListener( 'orientationchange', function() { 243 | if ( this.resizeTo ) { 244 | clearTimeout( this.resizeTo ); 245 | } 246 | 247 | this.resizeTo = setTimeout( function() { 248 | for ( itemIndex = 0; itemIndex < self.resizeCacheArr.length; itemIndex++ ) { 249 | self.resizeCacheArr[ itemIndex ](); 250 | } 251 | }, 200 ); 252 | }, false ); 253 | } else { 254 | window.addEventListener( 'resize', function() { 255 | if ( this.resizeTo ) { 256 | clearTimeout( this.resizeTo ); 257 | } 258 | 259 | this.resizeTo = setTimeout( function() { 260 | for ( itemIndex = 0; itemIndex < self.resizeCacheArr.length; itemIndex++ ) { 261 | self.resizeCacheArr[ itemIndex ](); 262 | } 263 | }, 200 ); 264 | } ); 265 | } 266 | }; 267 | 268 | stVideo.prototype.resizeHandler = function( fn ) { 269 | this.resizeCacheArr = this.resizeCacheArr || []; 270 | 271 | fn(); 272 | 273 | this.resizeCacheArr.push( fn ); 274 | }; 275 | 276 | stVideo.prototype.supportedVideoFormat = function( video ) { 277 | var options = {}; 278 | 279 | if ( video.canPlayType( 'video/webm' ) === 'probably' || video.canPlayType( 'video/webm' ) === 'maybe' ) { 280 | options.ext = 'webm'; 281 | options.type = 'video/webm; codecs="vp8, vorbis"'; 282 | } else if ( video.canPlayType( 'video/mp4' ) === 'probably' || video.canPlayType( 'video/mp4' ) === 'maybe' ) { 283 | options.ext = 'mp4'; 284 | options.type = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'; 285 | } else if ( video.canPlayType( 'video/ogg' ) === 'probably' || video.canPlayType( 'video/ogg' ) === 'maybe' ) { 286 | options.ext = 'ogg'; 287 | options.type = 'video/ogg; codecs="theora, vorbis"'; 288 | } 289 | 290 | return options; 291 | }; 292 | 293 | stVideo.prototype.videoAudio = function( video ) { 294 | var self = this, tempEvent, volume; 295 | 296 | if ( video.mozHasAudio || Boolean( video.webkitAudioDecodedByteCount ) || Boolean( video.audioTracks && video.audioTracks.length ) ) { 297 | this.hasAudio = true; 298 | 299 | this.element.classList.add( this.classNames.hasAudio ); 300 | 301 | volume = document.createElement( 'div' ); 302 | volume.classList.add( this.classNames.volume ); 303 | 304 | this.elControls.appendChild( volume ); 305 | 306 | this.elVolume = volume; 307 | 308 | this.elVolume.addEventListener( 'click', tempEvent = function() { 309 | if ( self.isMuted ) { 310 | self.video.volume = self.settings.volume; 311 | 312 | if ( self.audio ) { 313 | self.audio.volume = self.settings.volume; 314 | 315 | self.audio.currentTime = self.video.currentTime; 316 | 317 | if ( self.isPlaying ) { 318 | self.audio.play(); 319 | } 320 | 321 | if ( self.iOS ) { 322 | self.changeState( 'muted', false ); 323 | } 324 | } 325 | } else { 326 | self.video.volume = 0.01; 327 | 328 | if ( self.audio ) { 329 | self.audio.volume = 0.01; // hmm doesn't work on iPhone 330 | self.audio.pause(); 331 | 332 | if ( self.iOS ) { 333 | self.changeState( 'muted', true ); 334 | } 335 | } 336 | } 337 | } ); 338 | this.eventsControlsCollection.push( tempEvent ); 339 | } else { 340 | this.hasAudio = false; 341 | } 342 | 343 | return this.hasAudio; 344 | }; 345 | 346 | stVideo.prototype.playerControls = function() { 347 | var self = this, poster, controls, timeline, progress, handle, playPause, play, duration; 348 | 349 | if ( this.settings.poster ) { 350 | poster = document.createElement( 'div' ); 351 | poster.classList.add( this.classNames.poster ); 352 | poster.style.backgroundImage = 'url(' + this.settings.poster + ')'; 353 | 354 | this.element.appendChild( poster ); 355 | } 356 | 357 | play = document.createElement( 'div' ); 358 | play.classList.add( this.classNames.play ); 359 | 360 | controls = document.createElement( 'div' ); 361 | controls.classList.add( this.classNames.controls ); 362 | 363 | playPause = document.createElement( 'div' ); 364 | playPause.classList.add( this.classNames.playPause ); 365 | 366 | timeline = document.createElement( 'div' ); 367 | timeline.classList.add( this.classNames.timeline ); 368 | 369 | progress = document.createElement( 'div' ); 370 | progress.classList.add( this.classNames.progress ); 371 | 372 | handle = document.createElement( 'div' ); 373 | handle.classList.add( this.classNames.handle ); 374 | 375 | duration = document.createElement( 'div' ); 376 | duration.classList.add( this.classNames.duration ); 377 | 378 | timeline.appendChild( progress ); 379 | timeline.appendChild( handle ); 380 | controls.appendChild( timeline ); 381 | controls.appendChild( playPause ); 382 | controls.appendChild( duration ); 383 | 384 | this.element.appendChild( controls ); 385 | this.element.appendChild( play ); 386 | 387 | this.elControls = controls; 388 | this.elPlay = play; 389 | this.elPlayPause = playPause; 390 | this.elTimeline = timeline; 391 | this.elProgress = progress; 392 | this.elHandle = handle; 393 | this.elDuration = duration; 394 | }; 395 | 396 | stVideo.prototype.addVideoListeners = function() { 397 | var self = this, tempEvent; 398 | 399 | this.video.addEventListener( 'loadedmetadata', tempEvent = function() { 400 | var audio = self.videoAudio( this ); 401 | 402 | if ( self.useCanvas && audio ) { 403 | self.canvasAudio(); 404 | } 405 | } ); 406 | self.eventsVideoCollection.push( tempEvent ); 407 | 408 | this.video.addEventListener( 'canplaythrough', tempEvent = function() { 409 | if ( self.useCanvas ) { 410 | self.canvasDrawFrame(); 411 | } 412 | 413 | self.progressUpdate(); 414 | 415 | setTimeout( function() { 416 | self.resizeHandler( function() { 417 | self.timelineSettings.wrapperWidth = self.elTimeline.offsetWidth; 418 | } ); 419 | }, 100 ); 420 | } ); 421 | self.eventsVideoCollection.push( tempEvent ); 422 | 423 | if ( !self.useCanvas ) { 424 | this.video.addEventListener( 'play', tempEvent = function() { 425 | self.changeState( 'play', true ); 426 | self.changeState( 'end', false ); 427 | } ); 428 | self.eventsVideoCollection.push( tempEvent ); 429 | 430 | this.video.addEventListener( 'pause', tempEvent = function() { 431 | self.changeState( 'pause', true ); 432 | self.changeState( 'play', false ); 433 | } ); 434 | self.eventsVideoCollection.push( tempEvent ); 435 | 436 | this.video.addEventListener( 'ended', tempEvent = function() { 437 | self.changeState( 'end', true ); 438 | self.changeState( 'play', false ); 439 | } ); 440 | self.eventsVideoCollection.push( tempEvent ); 441 | } 442 | 443 | this.video.addEventListener( 'timeupdate', tempEvent = function() { 444 | if ( self.useCanvas ) { 445 | self.canvasDrawFrame(); 446 | } 447 | 448 | self.progressUpdate(); 449 | } ); 450 | self.eventsVideoCollection.push( tempEvent ); 451 | 452 | this.video.addEventListener( 'volumechange', tempEvent = function() { 453 | if ( this.volume > 0.01 ) { 454 | self.changeState( 'muted', false ); 455 | } else { 456 | self.changeState( 'muted', true ); 457 | } 458 | } ); 459 | self.eventsVideoCollection.push( tempEvent ); 460 | 461 | this.video.addEventListener( 'error', tempEvent = function( ev ) { 462 | self.isError = true; 463 | 464 | self.error.custom( ev ); 465 | } ); 466 | self.eventsVideoCollection.push( tempEvent ); 467 | }; 468 | 469 | stVideo.prototype.addControlsListeners = function( controlsBox ) { 470 | var self = this, tempEvent; 471 | 472 | this.elPlay.addEventListener( 'click', tempEvent = function() { 473 | if ( !self.isPlaying ) { 474 | self.play(); 475 | } else { 476 | self.pause(); 477 | } 478 | } ); 479 | self.eventsControlsCollection.push( tempEvent ); 480 | 481 | this.elPlayPause.addEventListener( 'click', tempEvent = function() { 482 | if ( !self.isPlaying ) { 483 | self.play(); 484 | } else { 485 | self.pause(); 486 | } 487 | } ); 488 | self.eventsControlsCollection.push( tempEvent ); 489 | 490 | if ( !this.useTouch ) { 491 | document.body.addEventListener( 'mousedown', tempEvent = function( e ) { 492 | e.preventDefault(); 493 | 494 | self.timelineSettings.isHandleMoving = true; 495 | 496 | if ( self.isContained( self.elHandle, e ) ) { 497 | self.timelineSettings.touchObj = e; 498 | self.timelineSettings.posLeft = self.timelineSettings.lastPosLeft; 499 | self.timelineSettings.startX = parseInt( e.clientX ); 500 | 501 | self.timelineSettings.isMouseDown = true; 502 | 503 | self.changeState( 'handle', true ); 504 | } else if ( self.isContained( self.elTimeline, e ) ) { 505 | self.timelineSettings.touchObj = e; 506 | self.timelineSettings.posLeft = 0; 507 | self.timelineSettings.startX = parseInt( e.layerX ); 508 | 509 | var dist = self.timelineSettings.startX; 510 | 511 | self.moveHandle( dist, true ); 512 | 513 | self.timelineSettings.isHandleMoving = false; 514 | } else { 515 | self.timelineSettings.isHandleMoving = false; 516 | } 517 | }, false ); 518 | self.eventsControlsCollection.push( tempEvent ); 519 | 520 | document.body.addEventListener( 'mousemove', tempEvent = function( e ) { 521 | e.preventDefault(); 522 | 523 | if ( self.timelineSettings.isMouseDown && self.timelineSettings.isHandleMoving ) { 524 | self.timelineSettings.touchObj = e; 525 | 526 | var dist = parseInt( self.timelineSettings.touchObj.clientX ) - self.timelineSettings.startX; 527 | 528 | self.moveHandle( dist ); 529 | } 530 | }, false ); 531 | self.eventsControlsCollection.push( tempEvent ); 532 | 533 | document.body.addEventListener( 'mouseup', tempEvent = function( e ) { 534 | e.preventDefault(); 535 | 536 | if ( self.timelineSettings.isMouseDown ) { 537 | self.timelineSettings.touchObj = e; 538 | self.timelineSettings.posLeft = self.timelineSettings.lastPosLeft; 539 | self.timelineSettings.startX = parseInt( self.timelineSettings.touchObj.clientX ); 540 | 541 | self.timelineSettings.isMouseDown = false; 542 | 543 | self.moveHandle( 0, true ); 544 | 545 | self.changeState( 'handle', false ); 546 | 547 | self.timelineSettings.isHandleMoving = false; 548 | } 549 | }, false ); 550 | self.eventsControlsCollection.push( tempEvent ); 551 | 552 | } else { 553 | this.elHandle.addEventListener( 'touchstart', tempEvent = function( e ) { 554 | // e.preventDefault(); 555 | e.stopPropagation(); 556 | 557 | self.timelineSettings.isHandleMoving = true; 558 | 559 | self.timelineSettings.touchObj = e.changedTouches[ 0 ]; 560 | self.timelineSettings.posLeft = self.timelineSettings.lastPosLeft; 561 | self.timelineSettings.startX = parseInt( self.timelineSettings.touchObj.clientX ); 562 | 563 | self.changeState( 'handle', true ); 564 | }, false ); 565 | self.eventsControlsCollection.push( tempEvent ); 566 | 567 | this.elHandle.addEventListener( 'touchmove', tempEvent = function( e ) { 568 | 569 | if ( self.timelineSettings.isHandleMoving ) { 570 | // e.preventDefault(); 571 | e.stopPropagation(); 572 | 573 | self.timelineSettings.touchObj = e.changedTouches[ 0 ]; 574 | 575 | var dist = parseInt( self.timelineSettings.touchObj.clientX ) - self.timelineSettings.startX; 576 | 577 | self.moveHandle( dist ); 578 | } 579 | }, false ); 580 | self.eventsControlsCollection.push( tempEvent ); 581 | 582 | this.elHandle.addEventListener( 'touchend', tempEvent = function( e ) { 583 | e.preventDefault(); 584 | 585 | self.timelineSettings.posLeft = self.timelineSettings.lastPosLeft; 586 | 587 | self.moveHandle( 0, true ); 588 | 589 | self.changeState( 'handle', false ); 590 | 591 | self.timelineSettings.isHandleMoving = false; 592 | }, false ); 593 | self.eventsControlsCollection.push( tempEvent ); 594 | } 595 | }; 596 | 597 | stVideo.prototype.canvasAudio = function() { 598 | this.audio = document.createElement( 'audio' ); 599 | 600 | this.audio.innerHTML = this.video.innerHTML; 601 | 602 | this.audio.load(); 603 | }; 604 | 605 | stVideo.prototype.canvasControl = function( action ) { 606 | if ( action === 'play' || ( action === 'play' && this.isEnded ) ) { 607 | if ( this.isEnded ) { 608 | this.changeState( 'end', false ); 609 | 610 | this.video.currentTime = 0; 611 | 612 | if ( this.audio ) { 613 | this.audio.currentTime = 0; 614 | } 615 | 616 | this.lastTime = Date.now(); 617 | } 618 | 619 | if ( this.audio && this.isMuted !== true ) { 620 | this.audio.play(); 621 | } 622 | 623 | this.changeState( 'play', true ); 624 | 625 | this.animationFrame = root.requestAnimationFrame( this.canvasFrameUpdate.bind( this ) ); 626 | 627 | } else if ( action === 'pause' || action === 'ended' ) { 628 | if ( action === 'ended' ) { 629 | this.changeState( 'end', true ); 630 | } else { 631 | this.changeState( 'pause', true ); 632 | } 633 | 634 | if ( this.audio ) { 635 | this.audio.pause(); 636 | } 637 | 638 | this.changeState( 'play', false ); 639 | 640 | root.cancelAnimationFrame( this.animationFrame ); 641 | } 642 | }; 643 | 644 | stVideo.prototype.canvasFrameUpdate = function() { 645 | var time = Date.now(), 646 | elapsed = ( time - ( this.lastTime || time ) ) / 1000; 647 | 648 | if ( !elapsed || elapsed >= 1 / this.settings.framesPerSecond ) { 649 | this.video.currentTime = this.video.currentTime + elapsed; 650 | 651 | /* if(this.audio && Math.abs(this.audio.currentTime - this.video.currentTime) > 0.3){ 652 | this.audio.pause(); 653 | this.audio.currentTime = this.video.currentTime; 654 | this.audio.play(); 655 | } */ 656 | 657 | this.lastTime = time; 658 | } 659 | 660 | if ( this.video.currentTime >= this.video.duration ) { 661 | this.canvasControl( 'ended' ); 662 | } else { 663 | this.animationFrame = root.requestAnimationFrame( this.canvasFrameUpdate.bind( this ) ); 664 | } 665 | }; 666 | 667 | stVideo.prototype.canvasDrawFrame = function() { 668 | this.canvasContext.drawImage( this.video, 0, 0, this.settings.width, this.settings.height ); 669 | }; 670 | 671 | stVideo.prototype.progressUpdate = function( movedByDistance ) { 672 | var current = this.video.currentTime, 673 | duration = this.video.duration, 674 | timeline = this.timelineSettings; 675 | 676 | if ( movedByDistance ) { 677 | current = this.video.currentTime = ( movedByDistance / timeline.wrapperWidth ) * duration; 678 | } 679 | 680 | var progress = ( current / duration * timeline.wrapperWidth ).toFixed( 2 ); 681 | 682 | if ( progress < 0 ) { 683 | progress = 0; 684 | } else if ( progress > timeline.wrapperWidth ) { 685 | progress = timeline.wrapperWidth; 686 | } 687 | 688 | this.elProgress.style.width = +progress + 'px'; 689 | 690 | if ( !timeline.isHandleMoving ) { 691 | this.elHandle.style.left = +progress + 'px'; 692 | } 693 | 694 | this.elDuration.innerText = this.formatTime( current ) + ' / ' + this.formatTime( duration ); 695 | }; 696 | 697 | stVideo.prototype.formatTime = function( seconds ) { 698 | var min, sec; 699 | 700 | min = Math.floor( seconds / 60 ); 701 | min = ( min >= 10 ) ? min : '0' + min; 702 | sec = Math.floor( seconds % 60 ); 703 | sec = ( sec >= 10 ) ? sec : '0' + sec; 704 | 705 | return min + ':' + sec; 706 | }; 707 | 708 | stVideo.prototype.moveHandle = function( movedByDistance, touchEnd ) { 709 | var opt = this.timelineSettings; 710 | 711 | if ( !opt.isHandleMoving ) { 712 | return; 713 | } 714 | 715 | var direction = ( ( touchEnd ? opt.lastDistance : movedByDistance ) > 0 ) ? 'right' : 'left'; 716 | 717 | var newPosition = opt.posLeft + movedByDistance; 718 | 719 | if ( newPosition < 0 ) { 720 | newPosition = 0; 721 | } else if ( newPosition > opt.wrapperWidth ) { 722 | newPosition = opt.wrapperWidth; 723 | } 724 | 725 | this.elHandle.style.left = newPosition + 'px'; 726 | 727 | opt.lastPosLeft = newPosition; 728 | opt.lastDistance = movedByDistance; 729 | opt.lastDirection = direction; 730 | 731 | if ( touchEnd ) { 732 | this.progressUpdate( newPosition ); 733 | } 734 | }; 735 | 736 | stVideo.prototype.error = { 737 | badVideoFormat: function() { 738 | if ( this.useCanvas ) { 739 | console.error( 'Apple devices support only .mp4 format' ); 740 | } else { 741 | console.error( 'Best use .webm and .mp4 video formats' ); 742 | } 743 | 744 | this.element.classList.add( this.classNames.error ); 745 | }, 746 | checkSettings: function() { 747 | console.error( 'Check all required settings' ); 748 | 749 | this.element.classList.add( this.classNames.error ); 750 | }, 751 | custom: function( msg ) { 752 | console.error( msg ); 753 | 754 | this.element.classList.add( this.classNames.error ); 755 | } 756 | }; 757 | 758 | stVideo.prototype.on = function( name, callback ) { 759 | if ( this.isError ) { 760 | return; 761 | } 762 | 763 | var self = this, tempEvent; 764 | 765 | // this.allowedEvents = ['canplay', 'canplaythrough', 'play', 'playing', 'pause', 'ended', 'abort', 'error', 'timeupdate']; 766 | 767 | // if(this.allowedEvents.indexOf(name) == -1) return; 768 | 769 | this.video.addEventListener( name, tempEvent = function() { 770 | callback.call( this ); 771 | } ); 772 | 773 | tempEvent.fnName = name; 774 | 775 | self.eventsUserCollection.push( tempEvent ); 776 | }; 777 | 778 | stVideo.prototype.eventCallback = function( name ) { 779 | if ( this.useCanvas ) { 780 | for ( var k in this.eventsUserCollection ) { 781 | if ( this.eventsUserCollection[ k ].fnName === name ) { 782 | this.eventsUserCollection[ k ](); 783 | } 784 | } 785 | } 786 | }; 787 | 788 | stVideo.prototype.play = function() { 789 | if ( this.isError ) { 790 | return; 791 | } 792 | 793 | this.lastTime = Date.now(); 794 | 795 | if ( this.useCanvas ) { 796 | this.canvasControl( 'play' ); 797 | } else { 798 | this.video.play(); 799 | } 800 | }; 801 | 802 | stVideo.prototype.pause = function() { 803 | if ( this.isError ) { 804 | return; 805 | } 806 | 807 | if ( this.isPlaying ) { 808 | if ( this.useCanvas ) { 809 | this.canvasControl( 'pause' ); 810 | } else { 811 | this.video.pause(); 812 | } 813 | } 814 | }; 815 | 816 | stVideo.prototype.changeState = function( action, value ) { 817 | var ec = this.element.classList; 818 | 819 | if ( action === 'play' ) { 820 | this.isPlaying = value; 821 | 822 | if ( value ) { 823 | ec.add( this.classNames.isPlaying ); 824 | 825 | this.eventCallback( 'play' ); 826 | } else { 827 | ec.remove( this.classNames.isPlaying ); 828 | } 829 | } 830 | 831 | if ( action === 'pause' ) { 832 | this.isPaused = value; 833 | 834 | if ( value ) { 835 | ec.add( this.classNames.isPaused ); 836 | 837 | this.eventCallback( 'pause' ); 838 | } else { 839 | ec.remove( this.classNames.isPaused ); 840 | } 841 | } 842 | 843 | if ( action === 'end' ) { 844 | this.isEnded = value; 845 | 846 | if ( value ) { 847 | ec.add( this.classNames.isEnded ); 848 | 849 | this.eventCallback( 'end' ); 850 | } else { 851 | ec.remove( this.classNames.isEnded ); 852 | } 853 | } 854 | 855 | if ( action === 'muted' ) { 856 | this.isMuted = value; 857 | 858 | if ( value ) { 859 | ec.add( this.classNames.isMuted ); 860 | 861 | this.eventCallback( 'muted' ); 862 | } else { 863 | ec.remove( this.classNames.isMuted ); 864 | } 865 | } 866 | 867 | if ( action === 'handle' ) { 868 | this.isMuted = value; 869 | 870 | if ( value ) { 871 | ec.add( this.classNames.isHandle ); 872 | } else { 873 | ec.remove( this.classNames.isHandle ); 874 | } 875 | } 876 | }; 877 | 878 | stVideo.prototype.destroy = function() { 879 | 880 | }; 881 | 882 | return stVideo; 883 | } ); 884 | --------------------------------------------------------------------------------