├── .gitignore
├── .travis.yml
├── README.md
├── bower.json
├── demo
└── index.html
├── dist
├── vidBg.css
├── vidBg.js
├── vidBg.min.css
└── vidBg.min.js
├── gulpfile.coffee
├── karma.conf.js
├── package.json
├── src
├── vidBg.coffee
├── vidBg.scss
└── vidBgTemplate.html
└── test
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | coverage
2 | bower_components
3 | node_modules
4 | .sass-cache
5 | .DS_Store
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.10"
4 | before_install:
5 | - npm install -g bower
6 | - npm install -g gulp
7 | - npm install
8 | - bower install
9 | script:
10 | - gulp test
11 | after_script:
12 | - gulp coveralls
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | angular-video-background
2 | ========================
3 |
4 | > html5 fullscreen video background in angular
5 |
6 | [](https://travis-ci.org/2013gang/angular-video-background)
7 |
8 | ## Description
9 |
10 | Eye-catching fullscreen video background is adopted by many modern websites for telling their stories. If you want to tell your own story in angular, you now have a choice. Just provide the video resouces, you can have your stunning video background right away.
11 |
12 | ## Demo
13 | you can see a demo here :)
14 |
15 | ## Dependency
16 | + angular (*)
17 |
18 | ## How to get it
19 |
20 | ```bower install --save angular-video-background```
21 |
22 | or
23 |
24 | ```npm install --save angular-vidbg```
25 |
26 | ## Usage
27 |
28 | include 3rd dependencies (angular, lodash) and dist/vidBg.js in your js file
29 |
30 | include dist/vidBg.css in your css file
31 |
32 | then:
33 |
34 | ```html
35 | dynamic video change
75 | + detailed accessible information about your video including loading status, played range, etc.
76 | + testing on different browsers/devices
77 | + how to deal with legacy browsers and mobile
78 |
79 | ### Credits
80 | Inspired by this
81 |
82 | references: [1], [2], [3]
83 |
84 | ### License
85 | MIT
86 |
87 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-vidbg",
3 | "version": "0.0.12",
4 | "authors": [
5 | "2013gangli@gmail.com"
6 | ],
7 | "description": "Video background",
8 | "keywords": [
9 | "angular",
10 | "video",
11 | "background"
12 | ],
13 | "dependencies": {
14 | "angular": "*"
15 | },
16 | "devDependencies": {
17 | "angular-mocks": "*"
18 | },
19 | "license": "MIT",
20 | "main": [
21 | "dist/vidBg.css",
22 | "dist/vidBg.js"
23 | ],
24 | "ignore": [
25 | "**/.*",
26 | "node_modules",
27 | "bower_components",
28 | "test",
29 | "src",
30 | "Gruntfile.coffee",
31 | "gulpfile.coffee"
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
video
element.'
9 | }).directive('vidBg', [
10 | '$log', 'vidBgDefaults', function($log, vidBgDefaults) {
11 | return {
12 | restrict: 'E',
13 | templateUrl: 'vidBgTemplate.html',
14 | scope: {
15 | resources: '=',
16 | fullScreen: '=',
17 | poster: '=',
18 | pausePlay: '=',
19 | playInfo: '='
20 | },
21 | compile: function(ele, attr) {
22 | var appendResourceToDom, processResources, vid, vidEle;
23 | vid = ele.children().children();
24 | vidEle = vid.eq(0);
25 | processResources = function(resources) {
26 | var resourceMap;
27 | resourceMap = {};
28 | if (angular.isArray(resources)) {
29 | angular.forEach(resources, function(ele, index) {
30 | if (angular.isString(ele)) {
31 | if (ele.toUpperCase().indexOf('.WEBM', ele.length - '.WEBM'.length) !== -1) {
32 | resourceMap.webm = ele;
33 | } else if (ele.toUpperCase().indexOf('.MP4', ele.length - '.MP4'.length) !== -1) {
34 | resourceMap.mp4 = ele;
35 | } else if (ele.toUpperCase().indexOf('.OGV', ele.length - '.OGV'.length) !== -1) {
36 | resourceMap.ogv = ele;
37 | } else if (ele.toUpperCase().indexOf('.SWF', ele.length - '.SWF'.length) !== -1) {
38 | resourceMap.swf = ele;
39 | }
40 | }
41 | });
42 | }
43 | return resourceMap;
44 | };
45 | appendResourceToDom = function(resourceMap) {
46 | vid.children().eq(0).attr('src', resourceMap.webm ? resourceMap.webm : '');
47 | vid.children().eq(1).attr('src', resourceMap.mp4 ? resourceMap.mp4 : '');
48 | vid.children().eq(2).attr('src', resourceMap.ogv ? resourceMap.ogv : '');
49 | return vid.children().eq(3).children().eq(0).attr('value', resourceMap.swf ? resourceMap.swf : '');
50 | };
51 | return {
52 | pre: function(scope, ele, attr) {
53 | scope.posterUrl = scope.poster ? scope.poster : '';
54 | scope.resourceMap = processResources(scope.resources);
55 | scope.muted = (scope.$parent.$eval(attr.muted)) || vidBgDefaults.muted;
56 | scope.control = (scope.$parent.$eval(attr.control)) || vidBgDefaults.control;
57 | scope.loop = (scope.$parent.$eval(attr.loop)) || vidBgDefaults.loop;
58 | scope.autoPlay = (scope.$parent.$eval(attr.autoPlay)) || vidBgDefaults.autoPlay;
59 | scope.zIndex = +(scope.$parent.$eval(attr.zIndex)) || vidBgDefaults.zIndex;
60 | scope.errorMsg = (scope.$parent.$eval(attr.errorMsg)) || vidBgDefaults.errorMsg;
61 | scope.playInfo = {
62 | buffer: 0,
63 | played: 0
64 | };
65 | },
66 | post: function(scope, ele, attr) {
67 | appendResourceToDom(scope.resourceMap);
68 | if (!scope.loop) {
69 | vidEle.on('ended', function() {
70 | return this.addClass('vidBg-fade');
71 | });
72 | }
73 | scope.$watch('pausePlay', function(val) {
74 | if (val) {
75 | vidEle.addClass('vidBg-fade');
76 | return vidEle[0].pause();
77 | } else {
78 | vidEle.removeClass('vidBg-fade');
79 | return vidEle[0].play();
80 | }
81 | });
82 | scope.$watch('resources', function(val) {
83 | vidEle.removeClass('vidBg-fade');
84 | vidEle[0].pause();
85 | appendResourceToDom(processResources(val));
86 | vidEle[0].load();
87 | return vidEle[0].play();
88 | }, true);
89 | vidEle.on('progress', function() {
90 | if (this.buffered.length > 0) {
91 | scope.playInfo.buffer = this.buffered.end(0) / this.duration;
92 | return scope.$apply();
93 | }
94 | });
95 | return vidEle.on('timeupdate', function() {
96 | scope.playInfo.played = this.currentTime / this.duration;
97 | return scope.$apply();
98 | });
99 | }
100 | };
101 | }
102 | };
103 | }
104 | ]);
105 |
106 | }).call(this);
107 |
108 | (function(module) {
109 | try {
110 | module = angular.module('vidBgTemplate');
111 | } catch (e) {
112 | module = angular.module('vidBgTemplate', []);
113 | }
114 | module.run(['$templateCache', function($templateCache) {
115 | $templateCache.put('vidBgTemplate.html',
116 | 'video
element."}).directive("vidBg",["$log","vidBgDefaults",function(e,r){return{restrict:"E",templateUrl:"vidBgTemplate.html",scope:{resources:"=",fullScreen:"=",poster:"=",pausePlay:"=",playInfo:"="},compile:function(e,n){var t,a,o,l;return o=e.children().children(),l=o.eq(0),a=function(e){var r;return r={},angular.isArray(e)&&angular.forEach(e,function(e,n){angular.isString(e)&&(-1!==e.toUpperCase().indexOf(".WEBM",e.length-".WEBM".length)?r.webm=e:-1!==e.toUpperCase().indexOf(".MP4",e.length-".MP4".length)?r.mp4=e:-1!==e.toUpperCase().indexOf(".OGV",e.length-".OGV".length)?r.ogv=e:-1!==e.toUpperCase().indexOf(".SWF",e.length-".SWF".length)&&(r.swf=e))}),r},t=function(e){return o.children().eq(0).attr("src",e.webm?e.webm:""),o.children().eq(1).attr("src",e.mp4?e.mp4:""),o.children().eq(2).attr("src",e.ogv?e.ogv:""),o.children().eq(3).children().eq(0).attr("value",e.swf?e.swf:"")},{pre:function(e,n,t){e.posterUrl=e.poster?e.poster:"",e.resourceMap=a(e.resources),e.muted=e.$parent.$eval(t.muted)||r.muted,e.control=e.$parent.$eval(t.control)||r.control,e.loop=e.$parent.$eval(t.loop)||r.loop,e.autoPlay=e.$parent.$eval(t.autoPlay)||r.autoPlay,e.zIndex=+e.$parent.$eval(t.zIndex)||r.zIndex,e.errorMsg=e.$parent.$eval(t.errorMsg)||r.errorMsg,e.playInfo={buffer:0,played:0}},post:function(e,r,n){return t(e.resourceMap),e.loop||l.on("ended",function(){return this.addClass("vidBg-fade")}),e.$watch("pausePlay",function(e){return e?(l.addClass("vidBg-fade"),l[0].pause()):(l.removeClass("vidBg-fade"),l[0].play())}),e.$watch("resources",function(e){return l.removeClass("vidBg-fade"),l[0].pause(),t(a(e)),l[0].load(),l[0].play()},!0),l.on("progress",function(){return this.buffered.length>0?(e.playInfo.buffer=this.buffered.end(0)/this.duration,e.$apply()):void 0}),l.on("timeupdate",function(){return e.playInfo.played=this.currentTime/this.duration,e.$apply()})}}}}}])}).call(this),function(e){try{e=angular.module("vidBgTemplate")}catch(r){e=angular.module("vidBgTemplate",[])}e.run(["$templateCache",function(e){e.put("vidBgTemplate.html",'video
element.'
11 | .directive 'vidBg', ['$log', 'vidBgDefaults', ($log, vidBgDefaults) ->
12 | restrict: 'E'
13 | templateUrl: 'vidBgTemplate.html'
14 | scope:
15 | resources: '='
16 | fullScreen: '='
17 | poster: '='
18 | pausePlay: '='
19 | playInfo: '='
20 | compile: (ele, attr) ->
21 | vid = do ele.children().children
22 | vidEle = vid.eq 0
23 | processResources = (resources) ->
24 | resourceMap = {}
25 | if angular.isArray resources
26 | angular.forEach resources, (ele, index) ->
27 | if angular.isString ele
28 | if ele.toUpperCase().indexOf(
29 | '.WEBM', ele.length - '.WEBM'.length) isnt -1
30 | resourceMap.webm = ele
31 | return
32 | else if ele.toUpperCase().indexOf(
33 | '.MP4', ele.length - '.MP4'.length) isnt -1
34 | resourceMap.mp4 = ele
35 | return
36 | else if ele.toUpperCase().indexOf(
37 | '.OGV', ele.length - '.OGV'.length) isnt -1
38 | resourceMap.ogv = ele
39 | return
40 | else if ele.toUpperCase().indexOf(
41 | '.SWF', ele.length - '.SWF'.length) isnt -1
42 | resourceMap.swf = ele
43 | return
44 | return resourceMap
45 | appendResourceToDom = (resourceMap) ->
46 | # Need to mannually add src because of
47 | # https://docs.angularjs.org/api/ng/service/$sce
48 | vid.children()
49 | .eq(0).attr('src', if resourceMap.webm then resourceMap.webm else '')
50 |
51 | vid.children()
52 | .eq(1).attr('src', if resourceMap.mp4 then resourceMap.mp4 else '')
53 |
54 | vid.children()
55 | .eq(2).attr('src', if resourceMap.ogv then resourceMap.ogv else '')
56 |
57 | vid.children()
58 | .eq(3).children().eq(0)
59 | .attr('value', if resourceMap.swf then resourceMap.swf else '')
60 |
61 | pre: (scope, ele, attr) ->
62 | scope.posterUrl = if scope.poster then scope.poster else ''
63 | scope.resourceMap = processResources scope.resources
64 | scope.muted = (scope.$parent.$eval attr.muted) ||
65 | vidBgDefaults.muted
66 | scope.control = (scope.$parent.$eval attr.control) ||
67 | vidBgDefaults.control
68 | scope.loop = (scope.$parent.$eval attr.loop) ||
69 | vidBgDefaults.loop
70 | scope.autoPlay = (scope.$parent.$eval attr.autoPlay) ||
71 | vidBgDefaults.autoPlay
72 | scope.zIndex = +(scope.$parent.$eval attr.zIndex) ||
73 | vidBgDefaults.zIndex
74 | scope.errorMsg = (scope.$parent.$eval attr.errorMsg) ||
75 | vidBgDefaults.errorMsg
76 | scope.playInfo =
77 | buffer: 0
78 | played: 0
79 | return
80 |
81 | post: (scope, ele, attr) ->
82 | appendResourceToDom scope.resourceMap
83 | if !scope.loop
84 | vidEle.on 'ended', ->
85 | this.addClass 'vidBg-fade'
86 |
87 | scope.$watch 'pausePlay', (val) ->
88 | if (val)
89 | vidEle.addClass 'vidBg-fade'
90 | do vidEle[0].pause
91 | else
92 | vidEle.removeClass 'vidBg-fade'
93 | do vidEle[0].play
94 | scope.$watch 'resources', (val) ->
95 | vidEle.removeClass 'vidBg-fade'
96 | do vidEle[0].pause
97 | appendResourceToDom processResources val
98 | do vidEle[0].load
99 | do vidEle[0].play
100 | , true
101 |
102 | vidEle.on 'progress', ->
103 | if this.buffered.length > 0
104 | scope.playInfo.buffer = this.buffered.end(0) / this.duration
105 | do scope.$apply
106 | vidEle.on 'timeupdate', ->
107 | scope.playInfo.played = this.currentTime / this.duration
108 | do scope.$apply
109 |
110 | ]
111 |
--------------------------------------------------------------------------------
/src/vidBg.scss:
--------------------------------------------------------------------------------
1 | video.vidBg-body {
2 | background-size: cover;
3 | transition: 1s opacity;
4 | }
5 |
6 | video.vidBg-fade {
7 | opacity: .5;
8 | }
9 |
10 | video.vidBg-fullScreen {
11 | position: fixed;
12 | right: 0;
13 | bottom: 0;
14 | min-width: 100%;
15 | min-height: 100%;
16 | width: auto;
17 | height: auto;
18 | }
19 |
20 | video.vidBg-autoWidth {
21 | width: 100%;
22 | height: auto;
23 | }
--------------------------------------------------------------------------------
/src/vidBgTemplate.html:
--------------------------------------------------------------------------------
1 |