popcornjs-rails 1.0.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Rails 3.1 asset-pipeline gem to provide popcorn.js
1
+ Rails 3.1 asset-pipeline gem to provide popcorn.js support
2
2
 
3
3
  # Install
4
4
 
@@ -9,17 +9,17 @@ Rails 3.1 asset-pipeline gem to provide popcorn.js
9
9
 
10
10
  In your application.js manifest:
11
11
 
12
- For full version:
12
+ ## For full version:
13
13
  //= popcorn
14
-
15
- Minified
14
+
15
+ ## Minified
16
16
  //= popcorn.min
17
-
18
- Full with all plugins
17
+
18
+ ## Full with all plugins
19
19
  //= popcorn-complete
20
-
21
- Full with all plugins and minified
20
+
21
+ ## Full with all plugins and minified
22
22
  //= popcorn-complete.min
23
-
23
+
24
24
  or directly available under `/assets/popcorn.js`
25
25
 
@@ -1,5 +1,5 @@
1
1
  module Popcornjs
2
2
  module Rails
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.2"
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  /*
2
- * popcorn.js version 1.0
2
+ * popcorn.js version 1.1.2
3
3
  * http://popcornjs.org
4
4
  *
5
5
  * Copyright 2011, Mozilla Foundation
@@ -129,7 +129,7 @@
129
129
  };
130
130
 
131
131
  // Popcorn API version, automatically inserted via build system.
132
- Popcorn.version = "1.0";
132
+ Popcorn.version = "1.1.2";
133
133
 
134
134
  // Boolean flag allowing a client to determine if Popcorn can be supported
135
135
  Popcorn.isSupported = true;
@@ -1050,8 +1050,11 @@
1050
1050
  end = tracks.endIndex,
1051
1051
  start = tracks.startIndex,
1052
1052
  animIndex = 0,
1053
-
1053
+ byStartLen = tracks.byStart.length,
1054
+ byEndLen = tracks.byEnd.length,
1054
1055
  registryByName = Popcorn.registryByName,
1056
+ trackstart = "trackstart",
1057
+ trackend = "trackend",
1055
1058
 
1056
1059
  byEnd, byStart, byAnimate, natives, type;
1057
1060
 
@@ -1072,6 +1075,13 @@
1072
1075
  if ( byEnd._running === true ) {
1073
1076
  byEnd._running = false;
1074
1077
  natives.end.call( obj, event, byEnd );
1078
+
1079
+ obj.trigger( trackend,
1080
+ Popcorn.extend({}, byEnd, {
1081
+ plugin: type,
1082
+ type: trackend
1083
+ })
1084
+ );
1075
1085
  }
1076
1086
 
1077
1087
  end++;
@@ -1100,6 +1110,13 @@
1100
1110
  byStart._running = true;
1101
1111
  natives.start.call( obj, event, byStart );
1102
1112
 
1113
+ obj.trigger( trackstart,
1114
+ Popcorn.extend({}, byStart, {
1115
+ plugin: type,
1116
+ type: trackstart
1117
+ })
1118
+ );
1119
+
1103
1120
  // If the `frameAnimation` option is used,
1104
1121
  // push the current byStart object into the `animating` cue
1105
1122
  if ( obj.options.frameAnimation &&
@@ -1149,6 +1166,13 @@
1149
1166
  if ( byStart._running === true ) {
1150
1167
  byStart._running = false;
1151
1168
  natives.end.call( obj, event, byStart );
1169
+
1170
+ obj.trigger( trackend,
1171
+ Popcorn.extend({}, byEnd, {
1172
+ plugin: type,
1173
+ type: trackend
1174
+ })
1175
+ );
1152
1176
  }
1153
1177
  start--;
1154
1178
  } else {
@@ -1176,6 +1200,12 @@
1176
1200
  byEnd._running = true;
1177
1201
  natives.start.call( obj, event, byEnd );
1178
1202
 
1203
+ obj.trigger( trackstart,
1204
+ Popcorn.extend({}, byStart, {
1205
+ plugin: type,
1206
+ type: trackstart
1207
+ })
1208
+ );
1179
1209
  // If the `frameAnimation` option is used,
1180
1210
  // push the current byEnd object into the `animating` cue
1181
1211
  if ( obj.options.frameAnimation &&
@@ -1213,6 +1243,11 @@
1213
1243
  tracks.endIndex = end;
1214
1244
  tracks.startIndex = start;
1215
1245
  tracks.previousUpdateTime = currentTime;
1246
+
1247
+ //enforce index integrity if trackRemoved
1248
+ tracks.byStart.length < byStartLen && tracks.startIndex--;
1249
+ tracks.byEnd.length < byEndLen && tracks.endIndex--;
1250
+
1216
1251
  };
1217
1252
 
1218
1253
  // Map and Extend TrackEvent functions to all Popcorn instances
@@ -4776,58 +4811,7 @@ var googleCallback;
4776
4811
  (function ( Popcorn ) {
4777
4812
 
4778
4813
  var i = 1,
4779
- scriptLoaded = false,
4780
-
4781
- dynamicFeedLoad = function() {
4782
- var dontLoad = false,
4783
- k = 0,
4784
- links = document.getElementsByTagName( "link" ),
4785
- len = links.length,
4786
- head = document.head || document.getElementsByTagName( "head" )[ 0 ],
4787
- css = document.createElement( "link" ),
4788
- resource = "//www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.";
4789
-
4790
- if ( !window.GFdynamicFeedControl ) {
4791
-
4792
- Popcorn.getScript( resource + "js", function() {
4793
- scriptLoaded = true;
4794
- });
4795
-
4796
- } else {
4797
- scriptLoaded = true;
4798
- }
4799
-
4800
- // Checking if the css file is already included
4801
- for ( ; k < len; k++ ){
4802
- if ( links[ k ].href === resource + "css" ) {
4803
- dontLoad = true;
4804
- }
4805
- }
4806
-
4807
- if ( !dontLoad ) {
4808
- css.type = "text/css";
4809
- css.rel = "stylesheet";
4810
- css.href = resource + "css";
4811
- head.insertBefore( css, head.firstChild );
4812
- }
4813
- };
4814
-
4815
- if ( !window.google ) {
4816
-
4817
- Popcorn.getScript( "//www.google.com/jsapi", function() {
4818
-
4819
- google.load( "feeds", "1", {
4820
-
4821
- callback: function () {
4822
-
4823
- dynamicFeedLoad();
4824
- }
4825
- });
4826
- });
4827
-
4828
- } else {
4829
- dynamicFeedLoad();
4830
- }
4814
+ scriptLoaded = false;
4831
4815
 
4832
4816
  /**
4833
4817
  * googlefeed popcorn plug-in
@@ -4855,6 +4839,57 @@ var googleCallback;
4855
4839
 
4856
4840
  Popcorn.plugin( "googlefeed", function( options ) {
4857
4841
 
4842
+ var dynamicFeedLoad = function() {
4843
+ var dontLoad = false,
4844
+ k = 0,
4845
+ links = document.getElementsByTagName( "link" ),
4846
+ len = links.length,
4847
+ head = document.head || document.getElementsByTagName( "head" )[ 0 ],
4848
+ css = document.createElement( "link" ),
4849
+ resource = "//www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.";
4850
+
4851
+ if ( !window.GFdynamicFeedControl ) {
4852
+
4853
+ Popcorn.getScript( resource + "js", function() {
4854
+ scriptLoaded = true;
4855
+ });
4856
+
4857
+ } else {
4858
+ scriptLoaded = true;
4859
+ }
4860
+
4861
+ // Checking if the css file is already included
4862
+ for ( ; k < len; k++ ){
4863
+ if ( links[ k ].href === resource + "css" ) {
4864
+ dontLoad = true;
4865
+ }
4866
+ }
4867
+
4868
+ if ( !dontLoad ) {
4869
+ css.type = "text/css";
4870
+ css.rel = "stylesheet";
4871
+ css.href = resource + "css";
4872
+ head.insertBefore( css, head.firstChild );
4873
+ }
4874
+ };
4875
+
4876
+ if ( !window.google ) {
4877
+
4878
+ Popcorn.getScript( "//www.google.com/jsapi", function() {
4879
+
4880
+ google.load( "feeds", "1", {
4881
+
4882
+ callback: function () {
4883
+
4884
+ dynamicFeedLoad();
4885
+ }
4886
+ });
4887
+ });
4888
+
4889
+ } else {
4890
+ dynamicFeedLoad();
4891
+ }
4892
+
4858
4893
  // create a new div and append it to the parent div so nothing
4859
4894
  // that already exists in the parent div gets overwritten
4860
4895
  var newdiv = document.createElement( "div" ),
@@ -4961,7 +4996,7 @@ var googleCallback;
4961
4996
  (function ( Popcorn ) {
4962
4997
 
4963
4998
  var i = 0,
4964
- createDefaultContainer = function( context ) {
4999
+ createDefaultContainer = function( context, id ) {
4965
5000
 
4966
5001
  var ctxContainer = context.container = document.createElement( "div" ),
4967
5002
  style = ctxContainer.style,
@@ -4978,7 +5013,7 @@ var googleCallback;
4978
5013
  setTimeout( updatePosition, 10 );
4979
5014
  };
4980
5015
 
4981
- ctxContainer.id = Popcorn.guid();
5016
+ ctxContainer.id = id || Popcorn.guid();
4982
5017
  style.position = "absolute";
4983
5018
  style.color = "white";
4984
5019
  style.textShadow = "black 2px 2px 6px";
@@ -4988,6 +5023,8 @@ var googleCallback;
4988
5023
  updatePosition();
4989
5024
 
4990
5025
  context.media.parentNode.appendChild( ctxContainer );
5026
+
5027
+ return ctxContainer;
4991
5028
  };
4992
5029
 
4993
5030
  /**
@@ -5055,7 +5092,8 @@ var googleCallback;
5055
5092
 
5056
5093
  // if a target is specified, use that
5057
5094
  if ( options.target && options.target !== "subtitle-container" ) {
5058
- options.container = document.getElementById( options.target );
5095
+ // In case the target doesn't exist in the DOM
5096
+ options.container = document.getElementById( options.target ) || createDefaultContainer( this, options.target );
5059
5097
  } else {
5060
5098
  // use shared default container
5061
5099
  options.container = this.container;
@@ -5710,6 +5748,417 @@ var wikiCallback;
5710
5748
  });
5711
5749
 
5712
5750
  })( Popcorn );
5751
+ // PLUGIN: Tumblr
5752
+
5753
+ (function( Popcorn, global ) {
5754
+
5755
+ /**
5756
+ * Tumblr Popcorn Plugin.
5757
+ * Adds elements to the page from selected blog.
5758
+ * Start is the time that you want this plug-in to execute
5759
+ * End is the time that you want this plug-in to stop executing
5760
+ * ApiKey is the API key registered with Tumblr for use with their API.
5761
+ * The ApiKey is required for Blog Info and to retrieve published blog
5762
+ * posts.
5763
+ *
5764
+ * Test tumblr site is here: http://tumblrplugin.tumblr.com/
5765
+ *
5766
+ * @param {Object} options
5767
+ *
5768
+ * Example:
5769
+ var p = Popcorn('#video')
5770
+ .tumblr({
5771
+ start: 5, // seconds, mandatory
5772
+ end: 15, // seconds, mandatory
5773
+ requestType: 'blogpost', // mandatory
5774
+ target: 'tumblrBlogInfodiv', // mandatory
5775
+ base_hostname: "john.io", // mandatory
5776
+ blogId: 123456789, // Mandatory if requestType is 'blogpost'
5777
+ api_key: ew29j2o1mw91m1wom1s9 // Mandatory is requestType is 'blogpost' or 'info'
5778
+ } )
5779
+ *
5780
+ */
5781
+
5782
+ var processBlogPost = {
5783
+ text: function( options ) {
5784
+ var post = options.post,
5785
+ link = document.createElement( "a" ),
5786
+ linkText = document.createTextNode( post.title ),
5787
+ linkDiv = document.createElement( "div" );
5788
+
5789
+ link.setAttribute( "href", post.post_url );
5790
+ link.appendChild( linkText );
5791
+ linkDiv.appendChild( link );
5792
+ linkDiv.innerHTML += post.body;
5793
+ options._container.appendChild( linkDiv );
5794
+
5795
+ },
5796
+ photo: function( options ) {
5797
+ var width = options.width || 250, defaultSizeIndex = -1,
5798
+ picCaptions = [ options.post.photos.length ],
5799
+ picURIs = [ options.post.photos.length ],
5800
+ picDiv = document.createElement( "div" ),
5801
+ pic = document.createElement( "img" ),
5802
+ post = options.post;
5803
+
5804
+ // Finds the correct photo based on specified size, saves URI and Caption]
5805
+ for ( var i = 0, len = post.photos.length; i < len; i++ ) {
5806
+ // Store the current photo object being accessed
5807
+ var photo = post.photos[ i ],
5808
+ photoSizes = photo.alt_sizes;
5809
+
5810
+ for ( var k = 0, len2 = photoSizes.length; k < len2; k++ ) {
5811
+ // Store the current alt_sizes object being accessed
5812
+ var size = photoSizes[ k ];
5813
+
5814
+ // See If users desired photo size is in returned JSON
5815
+ if ( size.width === width ) {
5816
+ picURIs[ i ] = size.url;
5817
+ picCaptions[ i ] = photo.caption;
5818
+ defaultSizeIndex = 0;
5819
+ break;
5820
+ } else {
5821
+ // Our default size is going to be 250
5822
+ if( size.width === 250 ){
5823
+ defaultSizeIndex = k;
5824
+ }
5825
+ }
5826
+ }
5827
+
5828
+ // Current means of handling if alt_sizes doesn't have our default image size
5829
+ defaultSizeIndex === -1 && Popcorn.error( "Clearly your blog has a picture that is so tiny it isn't even 250px wide. Consider " +
5830
+ " using a bigger picture or try a smaller size." );
5831
+
5832
+ // If a matching photo is never found, use the default size.
5833
+ if ( k === photoSizes.length ) {
5834
+ picURIs[ i ] = photoSizes[ defaultSizeIndex ].url;
5835
+ }
5836
+ }
5837
+
5838
+ // Finally, all the potential setup is done. Below is the actual code putting everything in our div element
5839
+ for ( var m = 0, len3 = picURIs.length; m < len3; m++ ) {
5840
+ picDiv.innerHTML += picCaptions[ m ] + "<br/>";
5841
+ pic.setAttribute( "src", picURIs[ m ] );
5842
+ pic.setAttribute( "alt", "Pic" + m );
5843
+ picDiv.appendChild( pic );
5844
+ picDiv.innerHTML += "<br/>";
5845
+ }
5846
+ picDiv.innerHTML += "<br/>" + post.caption;
5847
+ options._container.appendChild( picDiv );
5848
+ },
5849
+ audio: function( options ) {
5850
+ var artistDiv = document.createElement( "div" ),
5851
+ artistLink = document.createElement( "a" ),
5852
+ post = options.post;
5853
+ // Artist/Track info is not always returned so checking first.
5854
+ // Truth be told I have no idea if this will ever be returned. Their API specified it as responses but no
5855
+ // matter how much I tried myself to replicate it in a test I couldn't ever get a response that included
5856
+ // this info.
5857
+ if ( !post.artist ) {
5858
+ var artistText = document.createTextNode( post.source_title );
5859
+
5860
+ artistLink.setAttribute( "href", post.source_url );
5861
+ artistLink.appendChild( artistText );
5862
+ artistDiv.appendChild( artistLink );
5863
+ artistDiv.innerHTML += "<br/>";
5864
+ } else {
5865
+ var artistImage = document.createElement( "img" );
5866
+
5867
+ artistDiv.innerHTML += "Artist: " + post.artist + "<br/>";
5868
+ artistLink.setAttribute( "href", post.source_url );
5869
+
5870
+ // Construct Image
5871
+ artistImage.setAttribute( "src", post.album_art );
5872
+ artistImage.setAttribute( "alt", post.album );
5873
+
5874
+ // Set Image for link, append to div
5875
+ artistLink.appendChild( artistImage );
5876
+ artistDiv.appendChild( artistLink );
5877
+
5878
+ // Construct rest of plain old text
5879
+ artistDiv.innerHTML += "<hr/>" + post.track_number + " - " + post.track_name + "<br/>";
5880
+ }
5881
+ // Obviously the player itself is something that will be displayed either way so it is included outside the check
5882
+ artistDiv.innerHTML += post.player + " " + post.plays + "plays<br/>" + post.caption;
5883
+ options._container.appendChild( artistDiv );
5884
+ },
5885
+ video: function( options ) {
5886
+ var width = options.width || 400,
5887
+ defaultSizeIndex = -1,
5888
+ post = options.post,
5889
+ videoDiv = document.createElement( "div" ),
5890
+ videoCode;
5891
+
5892
+ for ( var i = 0, len = post.player.length; i < len; i++ ) {
5893
+ // First try to see if the current index matches the specified width
5894
+ // If it doesn't, check if it equals our default width incase user didn't
5895
+ // ever specify a width or if their width is never found.
5896
+
5897
+ // Store current player object being accessed
5898
+ var video = post.player[ i ];
5899
+
5900
+ if ( video.width === width ) {
5901
+ videoCode = video.embed_code;
5902
+ defaultSizeIndex = 0;
5903
+ break;
5904
+ } else {
5905
+ if( video.width === 400 ) {
5906
+ defaultSizeIndex = i;
5907
+ }
5908
+ }
5909
+ }
5910
+
5911
+ // If specified width never found, use default
5912
+ if ( i === options.post.player.length ) {
5913
+ videoCode = post.player[ defaultSizeIndex ].embed_code;
5914
+ }
5915
+
5916
+ // Will run if user's size is never found and our default is never found
5917
+ defaultSizeIndex === -1 && Popcorn.error( "Specified video size was not found and default was never found. Please try another width." );
5918
+
5919
+ // Finally build the html for the div element
5920
+ videoDiv.innerHTML += videoCode + "<br/>" + post.caption;
5921
+ options._container.appendChild( videoDiv );
5922
+ },
5923
+ chat: function( options ) {
5924
+ var post = options.post,
5925
+ dialogue,
5926
+ chatDiv = document.createElement( "div" );
5927
+
5928
+ // Brainstorm up ideas how to make each dialogue object to appear up "better" rather than just all be there at once
5929
+ chatDiv.innerHTML += "<strong><u>" + post.title + "</u></strong><br/><br/>";
5930
+
5931
+ for ( var i = 0, len = post.dialogue.length; i < len; i++ ) {
5932
+ dialogue = post.dialogue[ i ];
5933
+ chatDiv.innerHTML += dialogue.label + " " + dialogue.phrase + "<br/>";
5934
+ }
5935
+
5936
+ // Append it to the parent container
5937
+ options._container.appendChild( chatDiv );
5938
+ },
5939
+ quote: function( options ) {
5940
+ var quoteDiv = document.createElement( "div" ),
5941
+ quoteLink = document.createElement( "a" ),
5942
+ post = options.post,
5943
+ quoteLinkText = document.createTextNode( post.text );
5944
+
5945
+ // Quotes don't come with a title, so for a link to the post I'm going to use the blogname
5946
+ quoteLink.setAttribute( "href", post.post_url );
5947
+ quoteLink.appendChild( quoteLinkText );
5948
+
5949
+ // Append link, finish adding in plain text
5950
+ quoteDiv.appendChild( quoteLink );
5951
+ quoteDiv.innerHTML += "<br/><br/>Source: <b>" + post.source + "</b>";
5952
+
5953
+ // Append div to parent container
5954
+ options._container.appendChild( quoteDiv );
5955
+ },
5956
+ link: function( options ) {
5957
+ var linkDiv = document.createElement( "div" ),
5958
+ link = document.createElement( "a" ),
5959
+ post = options.post,
5960
+ linkText = document.createTextNode( post.title );
5961
+
5962
+ // Using the blog title as a link to it
5963
+ link.setAttribute( "href", post.post_url );
5964
+ link.appendChild( linkText );
5965
+ linkDiv.appendChild( link );
5966
+ linkDiv.innerHTML += "<br/>" + post.description;
5967
+
5968
+ // Append to parent container
5969
+ options._container.appendChild( linkDiv );
5970
+ },
5971
+ answer: function( options ) {
5972
+ var answerDiv = document.createElement( "div" ),
5973
+ link = document.createElement( "a" ),
5974
+ post = options.post,
5975
+ linkText = document.createTextNode( post.asking_name );
5976
+
5977
+ answerDiv.innerHTML = "Inquirer: ";
5978
+ link.setAttribute( "href", post.asking_url );
5979
+ link.appendChild( linkText );
5980
+ answerDiv.appendChild( link );
5981
+ answerDiv.innerHTML += "<br/><br/>Question: " + post.question + "<br/>Answer: " + post.answer;
5982
+
5983
+ // Append to parent container
5984
+ options._container.appendChild( answerDiv );
5985
+ }
5986
+ };
5987
+
5988
+ Popcorn.plugin( "tumblr" , {
5989
+ manifest: {
5990
+ about: {
5991
+ name: "Popcorn Tumblr Plugin",
5992
+ version: "0.1",
5993
+ author: "Matthew Schranz, @mjschranz",
5994
+ website: "mschranz.wordpress.com"
5995
+ },
5996
+ options: {
5997
+ requestType: {
5998
+ elem: "select",
5999
+ options:[ "INFO", "AVATAR", "BLOGPOST" ],
6000
+ label: "Type_Of_Plugin"
6001
+ },
6002
+ target: "tumblr-container",
6003
+ start: {
6004
+ elem: "input",
6005
+ type: "number",
6006
+ label: "Start_Time"
6007
+ },
6008
+ end: {
6009
+ elem: "input",
6010
+ type: "number",
6011
+ label: "End_Time"
6012
+ },
6013
+ base_hostname: {
6014
+ elem: "input",
6015
+ type: "text",
6016
+ label: "User_Name"
6017
+ },
6018
+ // optional parameters:
6019
+ api_key: { // Required for Blog Info and Blog Post retrievals
6020
+ elem: "input",
6021
+ type: "text",
6022
+ label: "Application_Key"
6023
+ },
6024
+ size: {
6025
+ elem: "select",
6026
+ options: [ 16, 24, 30, 40, 48, 64, 96, 128, 512 ],
6027
+ label: "avatarSize"
6028
+ },
6029
+ blogId: { // Required for BLOGPOST requests
6030
+ elem: "input",
6031
+ type: "number",
6032
+ label: "Blog_ID"
6033
+ },
6034
+ /* Optional for Photo and Video BlogPosts, defaulted to 250 pixels for photos and 400 for videos if not provided or provided width
6035
+ * is not found in their arrays. If multiple videos or photos are in the blogpost then it will use this same size for all of them unless
6036
+ * it is not found, which it will then use the default. If default is not present an error will be thrown.
6037
+ */
6038
+ width: {
6039
+ elem: "input",
6040
+ type: "number",
6041
+ label: "Photo_Width"
6042
+ }
6043
+ }
6044
+ },
6045
+ _setup: function( options ) {
6046
+ var target = document.getElementById( options.target ),
6047
+ requestString,
6048
+ uri,
6049
+ blogHTTPHeader,
6050
+ uriNoHeader,
6051
+ uriFinal,
6052
+ type;
6053
+
6054
+ // Valid types of retrieval requests
6055
+ var validType = function( type ) {
6056
+ return ( [ "info", "avatar", "blogpost" ].indexOf( type ) > -1 );
6057
+ };
6058
+
6059
+ // Lowercase the types incase user enters it in another way
6060
+ options.requestType = options.requestType.toLowerCase();
6061
+
6062
+ // Check if blog url ( base_hostname ) is blank and api_key is included on info and blogpost requestType
6063
+ ( !options.base_hostname || ( !options.api_key && ( options.requestType === "info" || options.requestType === "blogpost" ) ) ) &&
6064
+ Popcorn.error( "Must provide a blog URL to the plugin and an api_key for Blog Info and Blog Post requests." );
6065
+
6066
+ // Check Request Type
6067
+ !validType( options.requestType ) && Popcorn.error( "Invalid tumblr plugin type." );
6068
+
6069
+ // Check if a blogID is supplied
6070
+ ( options.requestType === "blogpost" && options.blogId === undefined ) && Popcorn.error( "Error. BlogId required for blogpost requests" );
6071
+
6072
+ // Check if target container exists
6073
+ ( !target && Popcorn.plugin.debug ) && Popcorn.error( "Target Tumblr container doesn't exist." );
6074
+
6075
+ // Checks if user included any http header in the url and removes it if that's the case as request don't work with it
6076
+ uri = options.base_hostname.slice( ( options.base_hostname.indexOf( "/" ) + 2 ), options.base_hostname.length );
6077
+ blogHTTPHeader = options.base_hostname.slice( 0, ( options.base_hostname.indexOf( "/" ) + 2 ) );
6078
+ uriNoHeader = blogHTTPHeader === "http://" || blogHTTPHeader === "https://" ? uri : options.base_hostname;
6079
+ if ( uriNoHeader.indexOf( "/" ) > -1 ){
6080
+ uriNoHeader = uriNoHeader.slice( 0, uriNoHeader.indexOf( "/" ) );
6081
+ }
6082
+ options.base_hostname = uriNoHeader;
6083
+
6084
+ // Create seperate container for plugin
6085
+ options._container = document.createElement( "div" );
6086
+ options._container.id = "tumblrdiv-" + Popcorn.guid();
6087
+
6088
+ if ( options.requestType === "avatar" ) {
6089
+ options._container.innerHTML = "<img src=" + 'http://api.tumblr.com/v2/blog/' + options.base_hostname + '/avatar/' + options.size + " alt='BlogAvatar' />";
6090
+ } else {
6091
+ // Construct type based if it's a blogpost or blog info as request string differs
6092
+ if ( options.requestType === "blogpost" ) {
6093
+ type = "posts";
6094
+ } else {
6095
+ type = "info";
6096
+ }
6097
+ requestString = "http://api.tumblr.com/v2/blog/" + options.base_hostname + "/" + type + "?api_key=" + options.api_key + "&id=" + options.blogId +
6098
+ "&jsonp=tumblrCallBack";
6099
+
6100
+ Popcorn.getJSONP( requestString, function( data ) {
6101
+ if ( data.meta.msg === "OK" ) {
6102
+ var commonDiv = document.createElement( "div" );
6103
+ if ( options.requestType === "blogpost" ) {
6104
+ options.post = data.response.posts[ 0 ];
6105
+ var blogType = options.post.type,
6106
+ post = options.post,
6107
+ tags = post.tags;
6108
+
6109
+ // date is a response type common to all blogposts so it's in here to prevent duplicated code
6110
+ commonDiv.innerHTML = "Date Published: " + options.post.date.slice( 0, options.post.date.indexOf( " " ) ) + "<br/>";
6111
+ // Check if tags were used for the post, append them to commonDiv
6112
+ if ( tags.length !== 0 ) {
6113
+ commonDiv.innerHTML += "Tags: " + tags[ 0 ];
6114
+ for ( var i = 1, len = tags.length; i < len; i++ ) {
6115
+ commonDiv.innerHTML += ", " + tags[ i ];
6116
+ }
6117
+ } else {
6118
+ commonDiv.innerHTML += "Tags: No Tags Used";
6119
+ }
6120
+ // commonDiv is appended at two points because of the difference in how the information
6121
+ // is constructed between blogposts and bloginfo
6122
+ options._container.appendChild( commonDiv );
6123
+
6124
+ // Processes information and forms an information div based on what the blog type is
6125
+ processBlogPost[ blogType ]( options );
6126
+ } else {
6127
+ // Blog Info Requests
6128
+ var link = document.createElement( "a" ),
6129
+ blogInfo = data.response.blog,
6130
+ linkText = document.createTextNode( blogInfo.title );
6131
+
6132
+ link.setAttribute( "href", blogInfo.url );
6133
+ link.appendChild( linkText );
6134
+ commonDiv.appendChild( link );
6135
+ commonDiv.innerHTML += blogInfo.description;
6136
+ options._container.appendChild( commonDiv );
6137
+ }
6138
+ } else {
6139
+ // There was an error somewhere down the line that caused the request to fail.
6140
+ Popcorn.error( "Error. Request failed. Status code: " + data.meta.status + " - Message: " + data.meta.msg );
6141
+ }
6142
+ }, false );
6143
+ }
6144
+ options._container.style.display = "none";
6145
+ target && target.appendChild( options._container );
6146
+ },
6147
+ start: function( event, options ){
6148
+ if ( options._container ) {
6149
+ options._container.style.display = "";
6150
+ }
6151
+ },
6152
+ end: function( event, options ){
6153
+ if( options._container ) {
6154
+ options._container.style.display = "none";
6155
+ }
6156
+ },
6157
+ _teardown: function( options ){
6158
+ document.getElementById( options.target ) && document.getElementById( options.target ).removeChild( options._container );
6159
+ }
6160
+ });
6161
+ })( Popcorn, this );
5713
6162
  //PLUGIN: linkedin
5714
6163
 
5715
6164
  (function ( Popcorn ){
@@ -6875,14 +7324,7 @@ document.addEventListener( "click", function( event ) {
6875
7324
  *
6876
7325
  */
6877
7326
 
6878
- var i = 1,
6879
- head = document.getElementsByTagName( "head" )[ 0 ],
6880
- css = document.createElement( "link" );
6881
-
6882
- css.type = "text/css";
6883
- css.rel = "stylesheet";
6884
- css.href = "//popcornjs.org/code/plugins/timeline/popcorn.timeline.css";
6885
- head.insertBefore( css, head.firstChild );
7327
+ var i = 1;
6886
7328
 
6887
7329
  Popcorn.plugin( "timeline" , function( options ) {
6888
7330
 
@@ -6930,8 +7372,8 @@ document.addEventListener( "click", function( event ) {
6930
7372
  // Default to empty if not used
6931
7373
  //options.innerHTML = options.innerHTML || "";
6932
7374
 
6933
- contentDiv.innerHTML = "<p><span id='big'>" + options.title + "</span><br />" +
6934
- "<span id='mid'>" + options.text + "</span><br />" + options.innerHTML;
7375
+ contentDiv.innerHTML = "<p><span id='big' style='font-size:24px; line-height: 130%;' >" + options.title + "</span><br />" +
7376
+ "<span id='mid' style='font-size: 16px;'>" + options.text + "</span><br />" + options.innerHTML;
6935
7377
 
6936
7378
  return {
6937
7379
 
@@ -6998,72 +7440,326 @@ document.addEventListener( "click", function( event ) {
6998
7440
  });
6999
7441
 
7000
7442
  })( Popcorn );
7001
- // PARSER: 0.3 JSON
7002
-
7003
- (function (Popcorn) {
7004
- Popcorn.parser( "parseJSON", "JSON", function( data ) {
7443
+ // PLUGIN: documentcloud
7005
7444
 
7006
- // declare needed variables
7007
- var retObj = {
7008
- title: "",
7009
- remote: "",
7010
- data: []
7011
- },
7012
- manifestData = {},
7013
- dataObj = data;
7014
-
7015
-
7016
- /*
7017
- TODO: add support for filling in source children of the video element
7018
-
7019
-
7020
- remote: [
7021
- {
7022
- src: "whatever.mp4",
7023
- type: 'video/mp4; codecs="avc1, mp4a"'
7024
- },
7025
- {
7026
- src: "whatever.ogv",
7027
- type: 'video/ogg; codecs="theora, vorbis"'
7028
- }
7029
- ]
7445
+ (function( Popcorn, document ) {
7030
7446
 
7031
- */
7032
-
7033
-
7034
- Popcorn.forEach( dataObj.data, function ( obj, key ) {
7035
- retObj.data.push( obj );
7036
- });
7447
+ /**
7448
+ * Document Cloud popcorn plug-in
7449
+ *
7450
+ * @param {Object} options
7451
+ *
7452
+ * Example:
7453
+ * var p = Popcorn("#video")
7454
+ * // Let the pdf plugin load your PDF file for you using pdfUrl.
7455
+ * .documentcloud({
7456
+ * start: 45
7457
+ * url: "http://www.documentcloud.org/documents/70050-urbina-day-1-in-progress.html", // or .js
7458
+ * width: ...,
7459
+ * height: ...,
7460
+ * zoom: ...,
7461
+ * page: ...,
7462
+ * container: ...
7463
+ * });
7464
+
7465
+ api - https://github.com/documentcloud/document-viewer/blob/master/public/javascripts/DV/controllers/api.js
7037
7466
 
7038
- return retObj;
7039
- });
7467
+ */
7040
7468
 
7041
- })( Popcorn );
7042
- // PARSER: 0.1 SBV
7469
+ // track registered plugins by document
7470
+ var documentRegistry = {};
7043
7471
 
7044
- (function (Popcorn) {
7472
+ Popcorn.plugin( "documentcloud", {
7045
7473
 
7046
- /**
7047
- * SBV popcorn parser plug-in
7048
- * Parses subtitle files in the SBV format.
7049
- * Times are expected in H:MM:SS.MIL format, with hours optional
7050
- * Subtitles which don't match expected format are ignored
7051
- * Data parameter is given by Popcorn, will need a text.
7052
- * Text is the file contents to be parsed
7053
- *
7054
- * @param {Object} data
7055
- *
7056
- * Example:
7057
- 0:00:02.400,0:00:07.200
7058
- Senator, we're making our final approach into Coruscant.
7059
- */
7060
- Popcorn.parser( "parseSBV", function( data ) {
7061
-
7062
- // declare needed variables
7063
- var retObj = {
7064
- title: "",
7065
- remote: "",
7066
- data: []
7474
+ manifest: {
7475
+ about: {
7476
+ name: "Popcorn Document Cloud Plugin",
7477
+ version: "0.1",
7478
+ author: "@humphd, @ChrisDeCairos",
7479
+ website: "http://vocamus.net/dave"
7480
+ },
7481
+ options: {
7482
+ start: {
7483
+ elem: "input",
7484
+ type: "text",
7485
+ label: "In"
7486
+ },
7487
+ end: {
7488
+ elem: "input",
7489
+ type: "text",
7490
+ label: "Out"
7491
+ },
7492
+ target: "documentcloud-container",
7493
+ width: {
7494
+ elem: "input",
7495
+ type: "text",
7496
+ label: "Width"
7497
+ },
7498
+ height: {
7499
+ elem: "input",
7500
+ type: "text",
7501
+ label: "Height"
7502
+ },
7503
+ src: {
7504
+ elem: "input",
7505
+ type: "text",
7506
+ label: "PDF URL"
7507
+ },
7508
+ preload: {
7509
+ elem: "input",
7510
+ type: "boolean",
7511
+ label: "Preload"
7512
+ },
7513
+ page: {
7514
+ elem: "input",
7515
+ type: "number",
7516
+ label: "Page Number"
7517
+ },
7518
+ aid: {
7519
+ elem: "input",
7520
+ type: "number",
7521
+ label: "Annotation Id"
7522
+ }
7523
+ }
7524
+ },
7525
+
7526
+ _setup: function( options ) {
7527
+ var DV = window.DV = window.DV || {},
7528
+ that = this;
7529
+
7530
+ //setup elem...
7531
+ function load() {
7532
+ DV.loaded = false;
7533
+ // swap .html URL to .js for API call
7534
+ var url = options.url.replace( /\.html$/, ".js" ),
7535
+ target = options.target,
7536
+ targetDiv = document.getElementById( target ),
7537
+ containerDiv = document.createElement( "div" ),
7538
+ containerDivSize = Popcorn.position( targetDiv ),
7539
+ // need to use size of div if not given
7540
+ width = options.width || containerDivSize.width,
7541
+ height = options.height || containerDivSize.height,
7542
+ sidebar = options.sidebar || true,
7543
+ text = options.text || true,
7544
+ pdf = options.pdf || true,
7545
+ showAnnotations = options.showAnnotations || true,
7546
+ zoom = options.zoom || 700,
7547
+ search = options.search || true,
7548
+ page = options.page,
7549
+ container;
7550
+
7551
+ function setOptions( viewer ) {
7552
+ options._key = viewer.api.getId();
7553
+
7554
+ options._changeView = function ( viewer ) {
7555
+ if ( options.aid ) {
7556
+ viewer.pageSet.showAnnotation( viewer.api.getAnnotation( options.aid ) );
7557
+ } else {
7558
+ viewer.api.setCurrentPage( options.page );
7559
+ }
7560
+ };
7561
+ }
7562
+
7563
+ function documentIsLoaded( url ) {
7564
+ var found = false;
7565
+ Popcorn.forEach( DV.viewers, function( viewer, idx ) {
7566
+ if( viewer.api.getSchema().canonicalURL === url ) {
7567
+ var targetDoc;
7568
+ setOptions( viewer );
7569
+ targetDoc = documentRegistry[ options._key ];
7570
+ options._containerId = targetDoc.id;
7571
+ targetDoc.num += 1;
7572
+ found = true;
7573
+ DV.loaded = true;
7574
+ }
7575
+ });
7576
+ return found;
7577
+ }
7578
+
7579
+ function createRegistryEntry() {
7580
+ var entry = {
7581
+ num: 1,
7582
+ id: options._containerId
7583
+ };
7584
+ documentRegistry[ options._key ] = entry;
7585
+ DV.loaded = true;
7586
+ }
7587
+
7588
+ if ( !documentIsLoaded( options.url ) ) {
7589
+
7590
+ containerDiv.id = options._containerId = Popcorn.guid( target );
7591
+ container = "#" + containerDiv.id;
7592
+ targetDiv.appendChild( containerDiv );
7593
+ that.trigger( "documentready" );
7594
+
7595
+ // Figure out if we need a callback to change the page #
7596
+ var afterLoad = options.page || options.aid ?
7597
+ function( viewer ) {
7598
+ setOptions( viewer );
7599
+ options._changeView( viewer );
7600
+ containerDiv.style.visibility = "hidden";
7601
+ viewer.elements.pages.hide();
7602
+ createRegistryEntry();
7603
+ } :
7604
+ function( viewer ) {
7605
+ setOptions( viewer );
7606
+ createRegistryEntry();
7607
+ containerDiv.style.visibility = "hidden";
7608
+ viewer.elements.pages.hide();
7609
+ };
7610
+ DV.load( url, {
7611
+ width: width,
7612
+ height: height,
7613
+ sidebar: sidebar,
7614
+ text: text,
7615
+ pdf: pdf,
7616
+ showAnnotations: showAnnotations,
7617
+ zoom: zoom,
7618
+ search: search,
7619
+ container: container,
7620
+ afterLoad: afterLoad
7621
+ });
7622
+ }
7623
+ }
7624
+ function readyCheck() {
7625
+ if( window.DV.loaded ) {
7626
+ load();
7627
+ } else {
7628
+ setTimeout( readyCheck, 25 );
7629
+ }
7630
+ }
7631
+
7632
+ // If the viewer is already loaded, don't repeat the process.
7633
+ if ( !DV.loading ) {
7634
+ DV.loading = true;
7635
+ DV.recordHit = "//www.documentcloud.org/pixel.gif";
7636
+
7637
+ var link = document.createElement( "link" ),
7638
+ head = document.getElementsByTagName( "head" )[ 0 ];
7639
+
7640
+ link.rel = "stylesheet";
7641
+ link.type = "text/css";
7642
+ link.media = "screen";
7643
+ link.href = "//s3.documentcloud.org/viewer/viewer-datauri.css";
7644
+
7645
+ head.appendChild( link );
7646
+
7647
+ // Record the fact that the viewer is loaded.
7648
+ DV.loaded = false;
7649
+
7650
+ // Request the viewer JavaScript.
7651
+ Popcorn.getScript( "http://s3.documentcloud.org/viewer/viewer.js", function() {
7652
+ DV.loading = false;
7653
+ load();
7654
+ });
7655
+ } else {
7656
+
7657
+ readyCheck();
7658
+ }
7659
+
7660
+ },
7661
+
7662
+ start: function( event, options ) {
7663
+ var elem = document.getElementById( options._containerId ),
7664
+ viewer = DV.viewers[ options._key ];
7665
+ ( options.page || options.aid ) && viewer &&
7666
+ options._changeView( viewer );
7667
+
7668
+ if ( elem && viewer) {
7669
+ elem.style.visibility = "visible";
7670
+ viewer.elements.pages.show();
7671
+ }
7672
+ },
7673
+
7674
+ end: function( event, options ) {
7675
+ var elem = document.getElementById( options._containerId );
7676
+
7677
+ if ( elem && DV.viewers[ options._key ] ) {
7678
+ elem.style.visibility = "hidden";
7679
+ DV.viewers[ options._key ].elements.pages.hide();
7680
+ }
7681
+ },
7682
+
7683
+ _teardown: function( options ) {
7684
+ var elem = document.getElementById( options._containerId ),
7685
+ key = options._key;
7686
+ if ( key && DV.viewers[ key ] && --documentRegistry[ key ].num === 0 ) {
7687
+ DV.viewers[ key ].api.unload();
7688
+
7689
+ while ( elem.hasChildNodes() ) {
7690
+ elem.removeChild( elem.lastChild );
7691
+ }
7692
+ elem.parentNode.removeChild( elem );
7693
+ }
7694
+ }
7695
+ });
7696
+ })( Popcorn, window.document );
7697
+ // PARSER: 0.3 JSON
7698
+
7699
+ (function (Popcorn) {
7700
+ Popcorn.parser( "parseJSON", "JSON", function( data ) {
7701
+
7702
+ // declare needed variables
7703
+ var retObj = {
7704
+ title: "",
7705
+ remote: "",
7706
+ data: []
7707
+ },
7708
+ manifestData = {},
7709
+ dataObj = data;
7710
+
7711
+
7712
+ /*
7713
+ TODO: add support for filling in source children of the video element
7714
+
7715
+
7716
+ remote: [
7717
+ {
7718
+ src: "whatever.mp4",
7719
+ type: 'video/mp4; codecs="avc1, mp4a"'
7720
+ },
7721
+ {
7722
+ src: "whatever.ogv",
7723
+ type: 'video/ogg; codecs="theora, vorbis"'
7724
+ }
7725
+ ]
7726
+
7727
+ */
7728
+
7729
+
7730
+ Popcorn.forEach( dataObj.data, function ( obj, key ) {
7731
+ retObj.data.push( obj );
7732
+ });
7733
+
7734
+ return retObj;
7735
+ });
7736
+
7737
+ })( Popcorn );
7738
+ // PARSER: 0.1 SBV
7739
+
7740
+ (function (Popcorn) {
7741
+
7742
+ /**
7743
+ * SBV popcorn parser plug-in
7744
+ * Parses subtitle files in the SBV format.
7745
+ * Times are expected in H:MM:SS.MIL format, with hours optional
7746
+ * Subtitles which don't match expected format are ignored
7747
+ * Data parameter is given by Popcorn, will need a text.
7748
+ * Text is the file contents to be parsed
7749
+ *
7750
+ * @param {Object} data
7751
+ *
7752
+ * Example:
7753
+ 0:00:02.400,0:00:07.200
7754
+ Senator, we're making our final approach into Coruscant.
7755
+ */
7756
+ Popcorn.parser( "parseSBV", function( data ) {
7757
+
7758
+ // declare needed variables
7759
+ var retObj = {
7760
+ title: "",
7761
+ remote: "",
7762
+ data: []
7067
7763
  },
7068
7764
  subs = [],
7069
7765
  lines,
@@ -8138,102 +8834,104 @@ document.addEventListener( "click", function( event ) {
8138
8834
  swfobject.embedSWF( "http://player.soundcloud.com/player.swf", self._playerId, self.offsetWidth, self.height, "9.0.0", "expressInstall.swf", flashvars, params, attributes );
8139
8835
  }
8140
8836
 
8141
- Popcorn.getScript( "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js" );
8142
8837
 
8143
- // Source file originally from 'https://github.com/soundcloud/Widget-JS-API/raw/master/soundcloud.player.api.js'
8144
- Popcorn.getScript( "http://popcornjs.org/code/players/soundcloud/lib/soundcloud.player.api.js", function() {
8145
- // Play event is fired twice when player is first started. Ignore second one
8146
- var ignorePlayEvt = 1;
8838
+ Popcorn.soundcloud = function( containerId, src, options ) {
8147
8839
 
8148
- // Register the wrapper's load event with the player
8149
- soundcloud.addEventListener( 'onPlayerReady', function( object, data ) {
8150
- var wrapper = registry[object.api_getFlashId()];
8840
+ Popcorn.getScript( "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js" );
8151
8841
 
8152
- wrapper.swfObj = object;
8153
- wrapper.duration = object.api_getTrackDuration();
8154
- wrapper.currentTime = object.api_getTrackPosition();
8155
- // This eliminates volumechangee event from firing on load
8156
- wrapper.volume = wrapper.previousVolume = object.api_getVolume()/100;
8842
+ // Source file originally from 'https://github.com/soundcloud/Widget-JS-API/raw/master/soundcloud.player.api.js'
8843
+ Popcorn.getScript( "http://popcornjs.org/code/players/soundcloud/lib/soundcloud.player.api.js", function() {
8844
+ // Play event is fired twice when player is first started. Ignore second one
8845
+ var ignorePlayEvt = 1;
8157
8846
 
8158
- // The numeric id of the track for use with Soundcloud API
8159
- wrapper._mediaId = data.mediaId;
8847
+ // Register the wrapper's load event with the player
8848
+ soundcloud.addEventListener( 'onPlayerReady', function( object, data ) {
8849
+ var wrapper = registry[object.api_getFlashId()];
8160
8850
 
8161
- wrapper.dispatchEvent( 'load' );
8162
- wrapper.dispatchEvent( 'canplay' );
8163
- wrapper.dispatchEvent( 'durationchange' );
8851
+ wrapper.swfObj = object;
8852
+ wrapper.duration = object.api_getTrackDuration();
8853
+ wrapper.currentTime = object.api_getTrackPosition();
8854
+ // This eliminates volumechangee event from firing on load
8855
+ wrapper.volume = wrapper.previousVolume = object.api_getVolume()/100;
8164
8856
 
8165
- wrapper.timeupdate();
8166
- });
8857
+ // The numeric id of the track for use with Soundcloud API
8858
+ wrapper._mediaId = data.mediaId;
8167
8859
 
8168
- // Register events for when the flash player plays a track for the first time
8169
- soundcloud.addEventListener( 'onMediaStart', function( object, data ) {
8170
- var wrapper = registry[object.api_getFlashId()];
8171
- wrapper.played = 1;
8172
- wrapper.dispatchEvent( 'playing' );
8173
- });
8860
+ wrapper.dispatchEvent( 'load' );
8861
+ wrapper.dispatchEvent( 'canplay' );
8862
+ wrapper.dispatchEvent( 'durationchange' );
8174
8863
 
8175
- // Register events for when the flash player plays a track
8176
- soundcloud.addEventListener( 'onMediaPlay', function( object, data ) {
8177
- if ( ignorePlayEvt ) {
8178
- ignorePlayEvt = 0;
8179
- return;
8180
- }
8864
+ wrapper.timeupdate();
8865
+ });
8181
8866
 
8182
- var wrapper = registry[object.api_getFlashId()];
8183
- wrapper.dispatchEvent( 'play' );
8184
- });
8867
+ // Register events for when the flash player plays a track for the first time
8868
+ soundcloud.addEventListener( 'onMediaStart', function( object, data ) {
8869
+ var wrapper = registry[object.api_getFlashId()];
8870
+ wrapper.played = 1;
8871
+ wrapper.dispatchEvent( 'playing' );
8872
+ });
8185
8873
 
8186
- // Register events for when the flash player pauses a track
8187
- soundcloud.addEventListener( 'onMediaPause', function( object, data ) {
8188
- var wrapper = registry[object.api_getFlashId()];
8189
- wrapper.dispatchEvent( 'pause' );
8190
- });
8874
+ // Register events for when the flash player plays a track
8875
+ soundcloud.addEventListener( 'onMediaPlay', function( object, data ) {
8876
+ if ( ignorePlayEvt ) {
8877
+ ignorePlayEvt = 0;
8878
+ return;
8879
+ }
8880
+
8881
+ var wrapper = registry[object.api_getFlashId()];
8882
+ wrapper.dispatchEvent( 'play' );
8883
+ });
8191
8884
 
8192
- // Register events for when the flash player is buffering
8193
- soundcloud.addEventListener( 'onMediaBuffering', function( object, data ) {
8194
- var wrapper = registry[object.api_getFlashId()];
8885
+ // Register events for when the flash player pauses a track
8886
+ soundcloud.addEventListener( 'onMediaPause', function( object, data ) {
8887
+ var wrapper = registry[object.api_getFlashId()];
8888
+ wrapper.dispatchEvent( 'pause' );
8889
+ });
8195
8890
 
8196
- wrapper.dispatchEvent( 'progress' );
8891
+ // Register events for when the flash player is buffering
8892
+ soundcloud.addEventListener( 'onMediaBuffering', function( object, data ) {
8893
+ var wrapper = registry[object.api_getFlashId()];
8197
8894
 
8198
- if ( wrapper.readyState === 0 ) {
8199
- wrapper.readyState = 3;
8200
- wrapper.dispatchEvent( "readystatechange" );
8201
- }
8202
- });
8895
+ wrapper.dispatchEvent( 'progress' );
8203
8896
 
8204
- // Register events for when the flash player is done buffering
8205
- soundcloud.addEventListener( 'onMediaDoneBuffering', function( object, data ) {
8206
- var wrapper = registry[object.api_getFlashId()];
8207
- wrapper.dispatchEvent( 'canplaythrough' );
8208
- });
8897
+ if ( wrapper.readyState === 0 ) {
8898
+ wrapper.readyState = 3;
8899
+ wrapper.dispatchEvent( "readystatechange" );
8900
+ }
8901
+ });
8209
8902
 
8210
- // Register events for when the flash player has finished playing
8211
- soundcloud.addEventListener( 'onMediaEnd', function( object, data ) {
8212
- var wrapper = registry[object.api_getFlashId()];
8213
- wrapper.paused = 1;
8214
- //wrapper.pause();
8215
- wrapper.dispatchEvent( 'ended' );
8216
- });
8903
+ // Register events for when the flash player is done buffering
8904
+ soundcloud.addEventListener( 'onMediaDoneBuffering', function( object, data ) {
8905
+ var wrapper = registry[object.api_getFlashId()];
8906
+ wrapper.dispatchEvent( 'canplaythrough' );
8907
+ });
8217
8908
 
8218
- // Register events for when the flash player has seeked
8219
- soundcloud.addEventListener( 'onMediaSeek', function( object, data ) {
8220
- var wrapper = registry[object.api_getFlashId()];
8909
+ // Register events for when the flash player has finished playing
8910
+ soundcloud.addEventListener( 'onMediaEnd', function( object, data ) {
8911
+ var wrapper = registry[object.api_getFlashId()];
8912
+ wrapper.paused = 1;
8913
+ //wrapper.pause();
8914
+ wrapper.dispatchEvent( 'ended' );
8915
+ });
8221
8916
 
8222
- wrapper.setCurrentTime( object.api_getTrackPosition() );
8917
+ // Register events for when the flash player has seeked
8918
+ soundcloud.addEventListener( 'onMediaSeek', function( object, data ) {
8919
+ var wrapper = registry[object.api_getFlashId()];
8223
8920
 
8224
- if ( wrapper.paused ) {
8225
- wrapper.dispatchEvent( "timeupdate" );
8226
- }
8227
- });
8921
+ wrapper.setCurrentTime( object.api_getTrackPosition() );
8922
+
8923
+ if ( wrapper.paused ) {
8924
+ wrapper.dispatchEvent( "timeupdate" );
8925
+ }
8926
+ });
8228
8927
 
8229
- // Register events for when the flash player has errored
8230
- soundcloud.addEventListener( 'onPlayerError', function( object, data ) {
8231
- var wrapper = registry[object.api_getFlashId()];
8232
- wrapper.dispatchEvent( 'error' );
8928
+ // Register events for when the flash player has errored
8929
+ soundcloud.addEventListener( 'onPlayerError', function( object, data ) {
8930
+ var wrapper = registry[object.api_getFlashId()];
8931
+ wrapper.dispatchEvent( 'error' );
8932
+ });
8233
8933
  });
8234
- });
8235
8934
 
8236
- Popcorn.soundcloud = function( containerId, src, options ) {
8237
8935
  return new Popcorn.soundcloud.init( containerId, src, options );
8238
8936
  };
8239
8937
 
@@ -8600,7 +9298,8 @@ document.addEventListener( "click", function( event ) {
8600
9298
  });
8601
9299
  }
8602
9300
  });
8603
- })( Popcorn, window );(function() {
9301
+ })( Popcorn, window );
9302
+ (function() {
8604
9303
 
8605
9304
  // global callback for vimeo.. yuck.
8606
9305
  vimeo_player_loaded = function( playerId ) {
@@ -8868,6 +9567,7 @@ var onYouTubePlayerReady = function( containerId ) {
8868
9567
  onYouTubePlayerReady[ containerId ] && onYouTubePlayerReady[ containerId ]();
8869
9568
  };
8870
9569
  onYouTubePlayerReady.stateChangeEventHandler = {};
9570
+ onYouTubePlayerReady.onErrorEventHandler = {};
8871
9571
 
8872
9572
  Popcorn.player( "youtube", {
8873
9573
  _setup: function( options ) {
@@ -8931,9 +9631,17 @@ Popcorn.player( "youtube", {
8931
9631
  }
8932
9632
  };
8933
9633
 
9634
+ onYouTubePlayerReady.onErrorEventHandler[ container.id ] = function( errorCode ) {
9635
+ if ( [ 2, 100, 101, 150 ].indexOf( errorCode ) !== -1 ) {
9636
+ media.dispatchEvent( "error" );
9637
+ }
9638
+ };
9639
+
8934
9640
  // youtube requires callbacks to be a string to a function path from the global scope
8935
9641
  youtubeObject.addEventListener( "onStateChange", "onYouTubePlayerReady.stateChangeEventHandler." + container.id );
8936
9642
 
9643
+ youtubeObject.addEventListener( "onError", "onYouTubePlayerReady.onErrorEventHandler." + container.id );
9644
+
8937
9645
  var timeupdate = function() {
8938
9646
 
8939
9647
  if ( !media.paused ) {
@@ -9088,542 +9796,6 @@ Popcorn.player( "youtube", {
9088
9796
  }
9089
9797
  });
9090
9798
 
9091
- /*!
9092
- * Popcorn.sequence
9093
- *
9094
- * Copyright 2011, Rick Waldron
9095
- * Licensed under MIT license.
9096
- *
9097
- */
9098
-
9099
- /* jslint forin: true, maxerr: 50, indent: 4, es5: true */
9100
- /* global Popcorn: true */
9101
-
9102
- // Requires Popcorn.js
9103
- (function( global, Popcorn ) {
9104
-
9105
- // TODO: as support increases, migrate to element.dataset
9106
- var doc = global.document,
9107
- location = global.location,
9108
- rprotocol = /:\/\//,
9109
- // TODO: better solution to this sucky stop-gap
9110
- lochref = location.href.replace( location.href.split("/").slice(-1)[0], "" ),
9111
- // privately held
9112
- range = function(start, stop, step) {
9113
-
9114
- start = start || 0;
9115
- stop = ( stop || start || 0 ) + 1;
9116
- step = step || 1;
9117
-
9118
- var len = Math.ceil((stop - start) / step) || 0,
9119
- idx = 0,
9120
- range = [];
9121
-
9122
- range.length = len;
9123
-
9124
- while (idx < len) {
9125
- range[idx++] = start;
9126
- start += step;
9127
- }
9128
- return range;
9129
- };
9130
-
9131
- Popcorn.sequence = function( parent, list ) {
9132
- return new Popcorn.sequence.init( parent, list );
9133
- };
9134
-
9135
- Popcorn.sequence.init = function( parent, list ) {
9136
-
9137
- // Video element
9138
- this.parent = doc.getElementById( parent );
9139
-
9140
- // Store ref to a special ID
9141
- this.seqId = Popcorn.guid( "__sequenced" );
9142
-
9143
- // List of HTMLVideoElements
9144
- this.queue = [];
9145
-
9146
- // List of Popcorn objects
9147
- this.playlist = [];
9148
-
9149
- // Lists of in/out points
9150
- this.inOuts = {
9151
-
9152
- // Stores the video in/out times for each video in sequence
9153
- ofVideos: [],
9154
-
9155
- // Stores the clip in/out times for each clip in sequences
9156
- ofClips: []
9157
-
9158
- };
9159
-
9160
- // Store first video dimensions
9161
- this.dims = {
9162
- width: 0, //this.video.videoWidth,
9163
- height: 0 //this.video.videoHeight
9164
- };
9165
-
9166
- this.active = 0;
9167
- this.cycling = false;
9168
- this.playing = false;
9169
-
9170
- this.times = {
9171
- last: 0
9172
- };
9173
-
9174
- // Store event pointers and queues
9175
- this.events = {
9176
-
9177
- };
9178
-
9179
- var self = this,
9180
- clipOffset = 0;
9181
-
9182
- // Create `video` elements
9183
- Popcorn.forEach( list, function( media, idx ) {
9184
-
9185
- var video = doc.createElement( "video" );
9186
-
9187
- video.preload = "auto";
9188
-
9189
- // Setup newly created video element
9190
- video.controls = true;
9191
-
9192
- // If the first, show it, if the after, hide it
9193
- video.style.display = ( idx && "none" ) || "" ;
9194
-
9195
- // Seta registered sequence id
9196
- video.id = self.seqId + "-" + idx ;
9197
-
9198
- // Push this video into the sequence queue
9199
- self.queue.push( video );
9200
-
9201
- var //satisfy lint
9202
- mIn = media["in"],
9203
- mOut = media["out"];
9204
-
9205
- // Push the in/out points into sequence ioVideos
9206
- self.inOuts.ofVideos.push({
9207
- "in": ( mIn !== undefined && mIn ) || 1,
9208
- "out": ( mOut !== undefined && mOut ) || 0
9209
- });
9210
-
9211
- self.inOuts.ofVideos[ idx ]["out"] = self.inOuts.ofVideos[ idx ]["out"] || self.inOuts.ofVideos[ idx ]["in"] + 2;
9212
-
9213
- // Set the sources
9214
- video.src = !rprotocol.test( media.src ) ? lochref + media.src : media.src;
9215
-
9216
- // Set some squence specific data vars
9217
- video.setAttribute("data-sequence-owner", parent );
9218
- video.setAttribute("data-sequence-guid", self.seqId );
9219
- video.setAttribute("data-sequence-id", idx );
9220
- video.setAttribute("data-sequence-clip", [ self.inOuts.ofVideos[ idx ]["in"], self.inOuts.ofVideos[ idx ]["out"] ].join(":") );
9221
-
9222
- // Append the video to the parent element
9223
- self.parent.appendChild( video );
9224
-
9225
-
9226
- self.playlist.push( Popcorn("#" + video.id ) );
9227
-
9228
- });
9229
-
9230
- self.inOuts.ofVideos.forEach(function( obj ) {
9231
-
9232
- var clipDuration = obj["out"] - obj["in"],
9233
- offs = {
9234
- "in": clipOffset,
9235
- "out": clipOffset + clipDuration
9236
- };
9237
-
9238
- self.inOuts.ofClips.push( offs );
9239
-
9240
- clipOffset = offs["out"] + 1;
9241
- });
9242
-
9243
- Popcorn.forEach( this.queue, function( media, idx ) {
9244
-
9245
- function canPlayThrough( event ) {
9246
-
9247
- // If this is idx zero, use it as dimension for all
9248
- if ( !idx ) {
9249
- self.dims.width = media.videoWidth;
9250
- self.dims.height = media.videoHeight;
9251
- }
9252
-
9253
- media.currentTime = self.inOuts.ofVideos[ idx ]["in"] - 0.5;
9254
-
9255
- media.removeEventListener( "canplaythrough", canPlayThrough, false );
9256
-
9257
- return true;
9258
- }
9259
-
9260
- // Hook up event listeners for managing special playback
9261
- media.addEventListener( "canplaythrough", canPlayThrough, false );
9262
-
9263
- // TODO: consolidate & DRY
9264
- media.addEventListener( "play", function( event ) {
9265
-
9266
- self.playing = true;
9267
-
9268
- }, false );
9269
-
9270
- media.addEventListener( "pause", function( event ) {
9271
-
9272
- self.playing = false;
9273
-
9274
- }, false );
9275
-
9276
- media.addEventListener( "timeupdate", function( event ) {
9277
-
9278
- var target = event.srcElement || event.target,
9279
- seqIdx = +( (target.dataset && target.dataset.sequenceId) || target.getAttribute("data-sequence-id") ),
9280
- floor = Math.floor( media.currentTime );
9281
-
9282
- if ( self.times.last !== floor &&
9283
- seqIdx === self.active ) {
9284
-
9285
- self.times.last = floor;
9286
-
9287
- if ( floor === self.inOuts.ofVideos[ seqIdx ]["out"] ) {
9288
-
9289
- Popcorn.sequence.cycle.call( self, seqIdx );
9290
- }
9291
- }
9292
- }, false );
9293
- });
9294
-
9295
- return this;
9296
- };
9297
-
9298
- Popcorn.sequence.init.prototype = Popcorn.sequence.prototype;
9299
-
9300
- //
9301
- Popcorn.sequence.cycle = function( idx ) {
9302
-
9303
- if ( !this.queue ) {
9304
- Popcorn.error("Popcorn.sequence.cycle is not a public method");
9305
- }
9306
-
9307
- var // Localize references
9308
- queue = this.queue,
9309
- ioVideos = this.inOuts.ofVideos,
9310
- current = queue[ idx ],
9311
- nextIdx = 0,
9312
- next, clip;
9313
-
9314
-
9315
- var // Popcorn instances
9316
- $popnext,
9317
- $popprev;
9318
-
9319
-
9320
- if ( queue[ idx + 1 ] ) {
9321
- nextIdx = idx + 1;
9322
- }
9323
-
9324
- // Reset queue
9325
- if ( !queue[ idx + 1 ] ) {
9326
-
9327
- nextIdx = 0;
9328
- this.playlist[ idx ].pause();
9329
-
9330
- } else {
9331
-
9332
- next = queue[ nextIdx ];
9333
- clip = ioVideos[ nextIdx ];
9334
-
9335
- // Constrain dimentions
9336
- Popcorn.extend( next, {
9337
- width: this.dims.width,
9338
- height: this.dims.height
9339
- });
9340
-
9341
- $popnext = this.playlist[ nextIdx ];
9342
- $popprev = this.playlist[ idx ];
9343
-
9344
- // When not resetting to 0
9345
- current.pause();
9346
-
9347
- this.active = nextIdx;
9348
- this.times.last = clip["in"] - 1;
9349
-
9350
- // Play the next video in the sequence
9351
- $popnext.currentTime( clip["in"] );
9352
-
9353
- $popnext[ nextIdx ? "play" : "pause" ]();
9354
-
9355
- // Trigger custom cycling event hook
9356
- this.trigger( "cycle", {
9357
-
9358
- position: {
9359
- previous: idx,
9360
- current: nextIdx
9361
- }
9362
-
9363
- });
9364
-
9365
- // Set the previous back to it's beginning time
9366
- // $popprev.currentTime( ioVideos[ idx ].in );
9367
-
9368
- if ( nextIdx ) {
9369
- // Hide the currently ending video
9370
- current.style.display = "none";
9371
- // Show the next video in the sequence
9372
- next.style.display = "";
9373
- }
9374
-
9375
- this.cycling = false;
9376
- }
9377
-
9378
- return this;
9379
- };
9380
-
9381
- var excludes = [ "timeupdate", "play", "pause" ];
9382
-
9383
- // Sequence object prototype
9384
- Popcorn.extend( Popcorn.sequence.prototype, {
9385
-
9386
- // Returns Popcorn object from sequence at index
9387
- eq: function( idx ) {
9388
- return this.playlist[ idx ];
9389
- },
9390
- // Remove a sequence from it's playback display container
9391
- remove: function() {
9392
- this.parent.innerHTML = null;
9393
- },
9394
- // Returns Clip object from sequence at index
9395
- clip: function( idx ) {
9396
- return this.inOuts.ofVideos[ idx ];
9397
- },
9398
- // Returns sum duration for all videos in sequence
9399
- duration: function() {
9400
-
9401
- var ret = 0,
9402
- seq = this.inOuts.ofClips,
9403
- idx = 0;
9404
-
9405
- for ( ; idx < seq.length; idx++ ) {
9406
- ret += seq[ idx ]["out"] - seq[ idx ]["in"] + 1;
9407
- }
9408
-
9409
- return ret - 1;
9410
- },
9411
-
9412
- play: function() {
9413
-
9414
- this.playlist[ this.active ].play();
9415
-
9416
- return this;
9417
- },
9418
- // Attach an event to a single point in time
9419
- exec: function ( time, fn ) {
9420
-
9421
- var index = this.active;
9422
-
9423
- this.inOuts.ofClips.forEach(function( off, idx ) {
9424
- if ( time >= off["in"] && time <= off["out"] ) {
9425
- index = idx;
9426
- }
9427
- });
9428
-
9429
- //offsetBy = time - self.inOuts.ofVideos[ index ].in;
9430
-
9431
- time += this.inOuts.ofVideos[ index ]["in"] - this.inOuts.ofClips[ index ]["in"];
9432
-
9433
- // Creating a one second track event with an empty end
9434
- Popcorn.addTrackEvent( this.playlist[ index ], {
9435
- start: time - 1,
9436
- end: time,
9437
- _running: false,
9438
- _natives: {
9439
- start: fn || Popcorn.nop,
9440
- end: Popcorn.nop,
9441
- type: "exec"
9442
- }
9443
- });
9444
-
9445
- return this;
9446
- },
9447
- // Binds event handlers that fire only when all
9448
- // videos in sequence have heard the event
9449
- listen: function( type, callback ) {
9450
-
9451
- var self = this,
9452
- seq = this.playlist,
9453
- total = seq.length,
9454
- count = 0,
9455
- fnName;
9456
-
9457
- if ( !callback ) {
9458
- callback = Popcorn.nop;
9459
- }
9460
-
9461
- // Handling for DOM and Media events
9462
- if ( Popcorn.Events.Natives.indexOf( type ) > -1 ) {
9463
- Popcorn.forEach( seq, function( video ) {
9464
-
9465
- video.listen( type, function( event ) {
9466
-
9467
- event.active = self;
9468
-
9469
- if ( excludes.indexOf( type ) > -1 ) {
9470
-
9471
- callback.call( video, event );
9472
-
9473
- } else {
9474
- if ( ++count === total ) {
9475
- callback.call( video, event );
9476
- }
9477
- }
9478
- });
9479
- });
9480
-
9481
- } else {
9482
-
9483
- // If no events registered with this name, create a cache
9484
- if ( !this.events[ type ] ) {
9485
- this.events[ type ] = {};
9486
- }
9487
-
9488
- // Normalize a callback name key
9489
- fnName = callback.name || Popcorn.guid( "__" + type );
9490
-
9491
- // Store in event cache
9492
- this.events[ type ][ fnName ] = callback;
9493
- }
9494
-
9495
- // Return the sequence object
9496
- return this;
9497
- },
9498
- unlisten: function( type, name ) {
9499
- // TODO: finish implementation
9500
- },
9501
- trigger: function( type, data ) {
9502
- var self = this;
9503
-
9504
- // Handling for DOM and Media events
9505
- if ( Popcorn.Events.Natives.indexOf( type ) > -1 ) {
9506
-
9507
- // find the active video and trigger api events on that video.
9508
- return;
9509
-
9510
- } else {
9511
-
9512
- // Only proceed if there are events of this type
9513
- // currently registered on the sequence
9514
- if ( this.events[ type ] ) {
9515
-
9516
- Popcorn.forEach( this.events[ type ], function( callback, name ) {
9517
- callback.call( self, { type: type }, data );
9518
- });
9519
-
9520
- }
9521
- }
9522
-
9523
- return this;
9524
- }
9525
- });
9526
-
9527
-
9528
- Popcorn.forEach( Popcorn.manifest, function( obj, plugin ) {
9529
-
9530
- // Implement passthrough methods to plugins
9531
- Popcorn.sequence.prototype[ plugin ] = function( options ) {
9532
-
9533
- // console.log( this, options );
9534
- var videos = {}, assignTo = [],
9535
- idx, off, inOuts, inIdx, outIdx, keys, clip, clipInOut, clipRange;
9536
-
9537
- for ( idx = 0; idx < this.inOuts.ofClips.length; idx++ ) {
9538
- // store reference
9539
- off = this.inOuts.ofClips[ idx ];
9540
- // array to test against
9541
- inOuts = range( off["in"], off["out"] );
9542
-
9543
- inIdx = inOuts.indexOf( options.start );
9544
- outIdx = inOuts.indexOf( options.end );
9545
-
9546
- if ( inIdx > -1 ) {
9547
- videos[ idx ] = Popcorn.extend( {}, off, {
9548
- start: inOuts[ inIdx ],
9549
- clipIdx: inIdx
9550
- });
9551
- }
9552
-
9553
- if ( outIdx > -1 ) {
9554
- videos[ idx ] = Popcorn.extend( {}, off, {
9555
- end: inOuts[ outIdx ],
9556
- clipIdx: outIdx
9557
- });
9558
- }
9559
- }
9560
-
9561
- keys = Object.keys( videos ).map(function( val ) {
9562
- return +val;
9563
- });
9564
-
9565
- assignTo = range( keys[ 0 ], keys[ 1 ] );
9566
-
9567
- //console.log( "PLUGIN CALL MAPS: ", videos, keys, assignTo );
9568
- for ( idx = 0; idx < assignTo.length; idx++ ) {
9569
-
9570
- var compile = {},
9571
- play = assignTo[ idx ],
9572
- vClip = videos[ play ];
9573
-
9574
- if ( vClip ) {
9575
-
9576
- // has instructions
9577
- clip = this.inOuts.ofVideos[ play ];
9578
- clipInOut = vClip.clipIdx;
9579
- clipRange = range( clip["in"], clip["out"] );
9580
-
9581
- if ( vClip.start ) {
9582
- compile.start = clipRange[ clipInOut ];
9583
- compile.end = clipRange[ clipRange.length - 1 ];
9584
- }
9585
-
9586
- if ( vClip.end ) {
9587
- compile.start = clipRange[ 0 ];
9588
- compile.end = clipRange[ clipInOut ];
9589
- }
9590
-
9591
- //compile.start += 0.1;
9592
- //compile.end += 0.9;
9593
-
9594
- } else {
9595
-
9596
- compile.start = this.inOuts.ofVideos[ play ]["in"];
9597
- compile.end = this.inOuts.ofVideos[ play ]["out"];
9598
-
9599
- //compile.start += 0.1;
9600
- //compile.end += 0.9;
9601
-
9602
- }
9603
-
9604
- // Handling full clip persistance
9605
- //if ( compile.start === compile.end ) {
9606
- //compile.start -= 0.1;
9607
- //compile.end += 0.9;
9608
- //}
9609
-
9610
- // Call the plugin on the appropriate Popcorn object in the playlist
9611
- // Merge original options object & compiled (start/end) object into
9612
- // a new fresh object
9613
- this.playlist[ play ][ plugin ](
9614
-
9615
- Popcorn.extend( {}, options, compile )
9616
-
9617
- );
9618
-
9619
- }
9620
-
9621
- // Return the sequence object
9622
- return this;
9623
- };
9624
-
9625
- });
9626
- })( this, Popcorn );
9627
9799
  // EFFECT: applyclass
9628
9800
 
9629
9801
  (function (Popcorn) {