popcornjs-rails 1.0.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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) {