Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

playback.js 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /*
  2. BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
  3. Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
  4. This program is free software; you can redistribute it and/or modify it under the
  5. terms of the GNU Lesser General Public License as published by the Free Software
  6. Foundation; either version 3.0 of the License, or (at your option) any later
  7. version.
  8. BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
  9. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  10. PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License along
  12. with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
  13. */
  14. goToSlide = function(time) {
  15. var pop = Popcorn("#video");
  16. pop.currentTime(time);
  17. };
  18. getUrlParameters = function() {
  19. var map = {};
  20. var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
  21. map[key] = value;
  22. });
  23. return map;
  24. };
  25. /*
  26. * From: http://stackoverflow.com/questions/1634748/how-can-i-delete-a-query-string-parameter-in-javascript/4827730#4827730
  27. */
  28. removeUrlParameter = function(url, param) {
  29. var urlparts= url.split('?');
  30. if (urlparts.length>=2) {
  31. var prefix= encodeURIComponent(param)+'=';
  32. var pars= urlparts[1].split(/[&;]/g);
  33. for (var i=pars.length; i-- > 0;) {
  34. if (pars[i].indexOf(prefix, 0)==0)
  35. pars.splice(i, 1);
  36. }
  37. if (pars.length > 0) {
  38. return urlparts[0]+'?'+pars.join('&');
  39. } else {
  40. return urlparts[0];
  41. }
  42. } else {
  43. return url;
  44. }
  45. }
  46. addUrlParameter = function(url, param, value) {
  47. var s = encodeURIComponent(param) + '=' + encodeURIComponent(value);
  48. console.log('Adding URL parameter ' + s);
  49. if (url.indexOf('?') == -1) {
  50. return url + '?' + s;
  51. } else {
  52. return url + '&' + s;
  53. }
  54. }
  55. /*
  56. * Converts seconds to HH:MM:SS
  57. * From: http://stackoverflow.com/questions/6312993/javascript-seconds-to-time-with-format-hhmmss#6313008
  58. */
  59. secondsToHHMMSS = function(secs) {
  60. var hours = Math.floor(secs / 3600);
  61. var minutes = Math.floor((secs - (hours * 3600)) / 60);
  62. var seconds = secs - (hours * 3600) - (minutes * 60);
  63. if (hours < 10) {hours = "0"+hours;}
  64. if (minutes < 10) {minutes = "0"+minutes;}
  65. if (seconds < 10) {seconds = "0"+seconds;}
  66. var time = hours+':'+minutes+':'+seconds;
  67. return time;
  68. }
  69. secondsToYouTubeFormat = function(secs) {
  70. var hours = Math.floor(secs / 3600);
  71. var minutes = Math.floor((secs - (hours * 3600)) / 60);
  72. var seconds = secs - (hours * 3600) - (minutes * 60);
  73. var time = "";
  74. if (hours > 0) {time += hours+"h";}
  75. if (minutes > 0) {time += minutes+"m";}
  76. if (seconds > 0) {time += seconds+"s";}
  77. if (secs == 0) {time = "0s";}
  78. return time;
  79. }
  80. /*
  81. * Full word version of the above function for screen readers
  82. */
  83. secondsToHHMMSSText = function(secs) {
  84. var hours = Math.floor(secs / 3600);
  85. var minutes = Math.floor((secs - (hours * 3600)) / 60);
  86. var seconds = secs - (hours * 3600) - (minutes * 60);
  87. var time = "";
  88. if (hours > 1) {time += hours + " hours ";}
  89. else if (hours == 1) {time += hours + " hour ";}
  90. if (minutes > 1) {time += minutes + " minutes ";}
  91. else if (minutes == 1) {time += minutes + " minute ";}
  92. if (seconds > 1) {time += seconds + " seconds ";}
  93. else if (seconds == 1) {time += seconds + " second ";}
  94. return time;
  95. }
  96. replaceTimeOnUrl = function(secs) {
  97. var newUrl = addUrlParameter(removeUrlParameter(document.URL, 't'), 't', secondsToYouTubeFormat(secs));
  98. window.history.replaceState({}, "", newUrl);
  99. }
  100. var params = getUrlParameters();
  101. var MEETINGID = params['meetingId'];
  102. var RECORDINGS = "/presentation/" + MEETINGID;
  103. var SLIDES_XML = RECORDINGS + '/slides_new.xml';
  104. var SHAPES_SVG = RECORDINGS + '/shapes.svg';
  105. var hasVideo = false;
  106. var syncing = false;
  107. var masterVideoSeeked = false;
  108. var primaryMedia;
  109. var secondaryMedias;
  110. var allMedias;
  111. /*
  112. * Sets the title attribute in a thumbnail.
  113. */
  114. setTitleOnThumbnail = function($thumb) {
  115. var src = $thumb.attr("src")
  116. if (src !== undefined) {
  117. var num = "?";
  118. var name = "undefined";
  119. var match = src.match(/slide-(.*).png/);
  120. if (match) { num = match[1]; }
  121. match = src.match(/([^/]*)\/slide-.*\.png/);
  122. if (match) { name = match[1]; }
  123. $thumb.attr("title", name + " (" + num + ")");
  124. }
  125. }
  126. /*
  127. * Associates several events on a thumbnail, e.g. click to change slide,
  128. * mouse over/out functions, etc.
  129. */
  130. setEventsOnThumbnail = function($thumb) {
  131. // Note: use ceil() so it jumps to a part of the video that actually is showing
  132. // this slide, while floor() would most likely jump to the previously slide
  133. // Popcorn event to mark a thumbnail when its slide is being shown
  134. var timeIn = $thumb.attr("data-in");
  135. var timeOut = $thumb.attr("data-out");
  136. var pop = Popcorn("#video");
  137. pop.code({
  138. start: timeIn,
  139. end: timeOut,
  140. onStart: function(options) {
  141. $parent = $(".thumbnail-wrapper").removeClass("active");
  142. $parent = $("#thumbnail-" + Math.ceil(options.start)).parent();
  143. $parent.addClass("active");
  144. animateToCurrentSlide();
  145. },
  146. onEnd: function(options) {
  147. $parent = $("#thumbnail-" + Math.ceil(options.start)).parent();
  148. $parent.removeClass("active");
  149. }
  150. });
  151. // Click on thumbnail changes the slide in popcorn
  152. $thumb.parent().on("click", function() {
  153. var time = Math.ceil($thumb.attr("data-in"));
  154. goToSlide(time);
  155. replaceTimeOnUrl(time);
  156. });
  157. // Mouse over/out to show/hide the label over the thumbnail
  158. $wrapper = $thumb.parent();
  159. $wrapper.on("mouseover", function() {
  160. $(this).addClass("hovered");
  161. });
  162. $wrapper.on("mouseout", function() {
  163. $(this).removeClass("hovered");
  164. });
  165. };
  166. var animateToCurrentSlide = function() {
  167. var $container = $("#thumbnails").parents(".left-off-canvas-menu");
  168. var currentThumb = $(".thumbnail-wrapper.active");
  169. // animate the scroll of thumbnails to center the current slide
  170. var thumbnailOffset = currentThumb.prop('offsetTop') - $container.prop('offsetTop') +
  171. (currentThumb.prop('offsetHeight') - $container.prop('offsetHeight')) / 2;
  172. $container.stop();
  173. $container.animate({ scrollTop: thumbnailOffset }, 200);
  174. };
  175. /*
  176. * Generates the list of thumbnails using shapes.svg
  177. */
  178. generateThumbnails = function() {
  179. console.log("== Generating thumbnails");
  180. var xmlhttp;
  181. if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
  182. xmlhttp = new XMLHttpRequest();
  183. } else {// code for IE6, IE5
  184. xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  185. }
  186. xmlhttp.open("GET", SHAPES_SVG, false);
  187. xmlhttp.send(null);
  188. if (xmlhttp.responseXML)
  189. var xmlDoc = xmlhttp.responseXML;
  190. else {
  191. var parser = new DOMParser();
  192. var xmlDoc = parser.parseFromString(xmlhttp.responseText, "image/svg+xml");
  193. }
  194. var elementsMap = {};
  195. var imagesList = new Array();
  196. xmlList = xmlDoc.getElementsByTagName("image");
  197. var slideCount = 0;
  198. console.log("== Setting title on thumbnails");
  199. for (var i = 0; i < xmlList.length; i++) {
  200. var element = xmlList[i];
  201. if (!$(element).attr("xlink:href"))
  202. continue;
  203. var src = RECORDINGS + "/" + element.getAttribute("xlink:href");
  204. if (src.match(/\/presentation\/.*slide-.*\.png/)) {
  205. var timeInList = xmlList[i].getAttribute("in").split(" ");
  206. var timeOutList = xmlList[i].getAttribute("out").split(" ");
  207. for (var j = 0; j < timeInList.length; j++) {
  208. var timeIn = Math.ceil(timeInList[j]);
  209. var timeOut = Math.ceil(timeOutList[j]);
  210. var img = $(document.createElement('img'));
  211. img.attr("src", src);
  212. img.attr("id", "thumbnail-" + timeIn);
  213. img.attr("data-in", timeIn);
  214. img.attr("data-out", timeOut);
  215. img.addClass("thumbnail");
  216. img.attr("alt", " ");
  217. img.attr("aria-hidden", "true"); //doesn't need to be focusable for blind users
  218. // a label with the time the slide starts
  219. var label = $(document.createElement('span'));
  220. label.addClass("thumbnail-label");
  221. label.attr("aria-hidden", "true"); //doesn't need to be focusable for blind users
  222. label.html(secondsToHHMMSS(timeIn));
  223. var hiddenDesc = $(document.createElement('span'));
  224. hiddenDesc.attr("id", img.attr("id") + "description");
  225. hiddenDesc.attr("class", "visually-hidden");
  226. hiddenDesc.html("Slide " + ++slideCount + " " + secondsToHHMMSSText(timeIn));
  227. // a wrapper around the img and label
  228. var div = $(document.createElement('div'));
  229. div.addClass("thumbnail-wrapper");
  230. div.attr("role", "link"); //tells accessibility software it can be clicked
  231. div.attr("aria-describedby", img.attr("id") + "description");
  232. div.append(img);
  233. div.append(label);
  234. div.append(hiddenDesc);
  235. if (parseFloat(timeIn) == 0) {
  236. div.addClass("active");
  237. }
  238. imagesList.push(timeIn);
  239. elementsMap[timeIn] = div;
  240. setEventsOnThumbnail(img);
  241. setTitleOnThumbnail(img);
  242. }
  243. }
  244. }
  245. imagesList.sort(function(a,b){return a - b});
  246. for (var i in imagesList) {
  247. $("#thumbnails").append(elementsMap[imagesList[i]]);
  248. }
  249. }
  250. function checkUrl(url)
  251. {
  252. console.log("==Checking Url",url);
  253. var http = new XMLHttpRequest();
  254. http.open('HEAD', url, false);
  255. try {
  256. http.send();
  257. } catch(e) {
  258. return false;
  259. }
  260. return http.status == 200 || http.status == 206;
  261. }
  262. load_video = function(){
  263. console.log("==Loading video");
  264. //document.getElementById("video").style.visibility = "hidden"
  265. var video = document.createElement("video");
  266. video.setAttribute('id','video');
  267. video.setAttribute('class','webcam');
  268. var webmsource = document.createElement("source");
  269. webmsource.setAttribute('src', RECORDINGS + '/video/webcams.webm');
  270. webmsource.setAttribute('type','video/webm; codecs="vp8.0, vorbis"');
  271. video.appendChild(webmsource);
  272. // Try to load the captions
  273. // TODO this all should be done asynchronously...
  274. var capReq = new XMLHttpRequest();
  275. capReq.open('GET', RECORDINGS + '/captions.json', /*async=*/false);
  276. capReq.send();
  277. if (capReq.status == 200) {
  278. console.log("==Loading closed captions");
  279. // With sync request, responseType should always be blank (=="text")
  280. var captions = JSON.parse(capReq.responseText);
  281. for (var i = 0; i < captions.length; i++) {
  282. var track = document.createElement("track");
  283. track.setAttribute('kind', 'captions');
  284. track.setAttribute('label', captions[i]['localeName']);
  285. track.setAttribute('srclang', captions[i]['locale']);
  286. track.setAttribute('src', RECORDINGS + '/caption_' + captions[i]['locale'] + '.vtt');
  287. video.appendChild(track);
  288. }
  289. }
  290. /*var time_manager = Popcorn("#video");
  291. var pc_webcam = Popcorn("#webcam");
  292. time_manager.on( "timeupdate", function() {
  293. pc_webcam.currentTime( this.currentTime() );
  294. });*/
  295. video.setAttribute('data-timeline-sources', SLIDES_XML);
  296. //video.setAttribute('controls','');
  297. //leave auto play turned off for accessiblity support
  298. //video.setAttribute('autoplay','autoplay');
  299. document.getElementById("video-area").appendChild(video);
  300. Popcorn("#video").on("canplayall", function() {
  301. console.log("==Video loaded");
  302. document.dispatchEvent(new CustomEvent('media-ready', {'detail': 'video'}));
  303. });
  304. }
  305. load_audio = function() {
  306. console.log("Loading audio")
  307. var audio = document.createElement("audio") ;
  308. audio.setAttribute('id', 'video');
  309. // The webm file will work in IE with WebM components installed,
  310. // and should load faster in Chrome too
  311. var webmsource = document.createElement("source");
  312. webmsource.setAttribute('src', RECORDINGS + '/audio/audio.webm');
  313. webmsource.setAttribute('type', 'audio/webm; codecs="vorbis"');
  314. // Need to keep the ogg source around for compat with old recordings
  315. var oggsource = document.createElement("source");
  316. oggsource.setAttribute('src', RECORDINGS + '/audio/audio.ogg');
  317. oggsource.setAttribute('type', 'audio/ogg; codecs="vorbis"');
  318. // Browser Bug Workaround: The ogg file should be preferred in Firefox,
  319. // since it can't seek in audio-only webm files.
  320. if (navigator.userAgent.indexOf("Firefox") != -1) {
  321. audio.appendChild(oggsource);
  322. audio.appendChild(webmsource);
  323. } else {
  324. audio.appendChild(webmsource);
  325. audio.appendChild(oggsource);
  326. }
  327. audio.setAttribute('data-timeline-sources', SLIDES_XML);
  328. //audio.setAttribute('controls','');
  329. //leave auto play turned off for accessiblity support
  330. //audio.setAttribute('autoplay','autoplay');
  331. document.getElementById("audio-area").appendChild(audio);
  332. //remember: audio id is 'video'
  333. Popcorn("#video").on("canplayall", function() {
  334. console.log("==Audio loaded");
  335. document.dispatchEvent(new CustomEvent('media-ready', {'detail': 'audio'}));
  336. });
  337. }
  338. load_deskshare_video = function () {
  339. console.log("==Loading deskshare video");
  340. var deskshare_video = document.createElement("video");
  341. deskshare_video.setAttribute('id','deskshare-video');
  342. var webmsource = document.createElement("source");
  343. webmsource.setAttribute('src', RECORDINGS + '/deskshare/deskshare.webm');
  344. webmsource.setAttribute('type','video/webm; codecs="vp8.0, vorbis"');
  345. deskshare_video.appendChild(webmsource);
  346. var presentationArea = document.getElementById("presentation-area");
  347. presentationArea.insertBefore(deskshare_video,presentationArea.childNodes[0]);
  348. setSync();
  349. Popcorn("#deskshare-video").on("canplayall", function() {
  350. console.log("==Deskshare video loaded");
  351. document.dispatchEvent(new CustomEvent('media-ready', {'detail': 'deskshare'}));
  352. });
  353. }
  354. function setSync() {
  355. //master video
  356. primaryMedia = Popcorn("#video");
  357. //slave videos
  358. secondaryMedias = [ Popcorn("#deskshare-video") ];
  359. allMedias = [primaryMedia].concat(secondaryMedias);
  360. //when we play the master video, we play all other videos as well...
  361. primaryMedia.on("play", function() {
  362. for(i = 0; i < secondaryMedias.length ; i++)
  363. secondaryMedias[i].play();
  364. });
  365. //when we pause the master video, we sync
  366. primaryMedia.on("pause", function() {
  367. sync();
  368. });
  369. primaryMedia.on("seeking", function() {
  370. if(primaryMedia.played().length != 0)
  371. masterVideoSeeked = true;
  372. });
  373. //when finished seeking, we sync all medias...
  374. primaryMedia.on("seeked", function() {
  375. if(primaryMedia.paused())
  376. sync();
  377. else
  378. primaryMedia.pause();
  379. });
  380. for(i = 0; i < allMedias.length ; i++) {
  381. allMedias[i].on("waiting", function() {
  382. //if one of the medias is 'waiting', we must sync
  383. if(!primaryMedia.seeking() && !syncing) {
  384. syncing = true;
  385. //pause the master video, causing to pause and sync all videos...
  386. console.log("syncing videos...");
  387. primaryMedia.pause();
  388. }
  389. });
  390. allMedias[i].on("canplaythrough", function() {
  391. if(syncing || masterVideoSeeked) {
  392. var allMediasAreReady = true;
  393. for(i = 0; i < allMedias.length ; i++)
  394. allMediasAreReady &= (allMedias[i].media.readyState == 4)
  395. if(allMediasAreReady) {
  396. syncing = false;
  397. masterVideoSeeked = false;
  398. //play the master video, causing to play all videos...
  399. console.log("resuming...");
  400. primaryMedia.play();
  401. }
  402. }
  403. });
  404. }
  405. }
  406. function sync() {
  407. for(var i = 0; i < secondaryMedias.length ; i++) {
  408. if(secondaryMedias[i].media.readyState > 1) {
  409. secondaryMedias[i].pause();
  410. //set the current time will fire a "canplaythrough" event to tell us that the video can be played...
  411. secondaryMedias[i].currentTime(primaryMedia.currentTime());
  412. }
  413. }
  414. }
  415. load_script = function(file){
  416. console.log("==Loading script "+ file)
  417. script = document.createElement('script');
  418. script.src = file;
  419. script.type = 'text/javascript';
  420. document.getElementsByTagName('body').item(0).appendChild(script);
  421. }
  422. document.addEventListener("DOMContentLoaded", function() {
  423. console.log("==DOM content loaded");
  424. var appName = navigator.appName;
  425. var appVersion = navigator.appVersion;
  426. startLoadingBar();
  427. if (checkUrl(RECORDINGS + '/video/webcams.webm') == true) {
  428. hasVideo = true;
  429. $("#audio-area").attr("style", "display:none;");
  430. load_video();
  431. } else {
  432. hasVideo = false;
  433. $("#video-area").attr("style", "display:none;");
  434. load_audio();
  435. }
  436. //load up the acorn controls
  437. console.log("==Loading acorn media player ");
  438. $('#video').acornMediaPlayer({
  439. theme: 'bigbluebutton',
  440. volumeSlider: 'vertical'
  441. });
  442. $('#video').on("swap", function() {
  443. swapVideoPresentation();
  444. });
  445. if (checkUrl(RECORDINGS + '/deskshare/deskshare.webm') == true) {
  446. load_deskshare_video();
  447. } else {
  448. // If there is no deskshare at all we must also trigger this event to signal Popcorn
  449. document.dispatchEvent(new CustomEvent('media-ready', {'detail': 'deskshare'}));
  450. }
  451. resizeComponents();
  452. }, false);
  453. var secondsToWait = 0;
  454. function addTime(time){
  455. if (secondsToWait === 0) {
  456. Popcorn('#video').pause();
  457. window.setTimeout("Tick()", 1000);
  458. }
  459. secondsToWait += time;
  460. }
  461. function Tick() {
  462. if (secondsToWait <= 0 || !($("#accEnabled").is(':checked'))) {
  463. secondsToWait = 0;
  464. Popcorn('#video').play();
  465. $('#countdown').html(""); // remove the timer
  466. return;
  467. }
  468. secondsToWait -= 1;
  469. $('#countdown').html(secondsToWait);
  470. window.setTimeout("Tick()", 1000);
  471. }
  472. // Swap the position of the DOM elements `elm1` and `elm2`.
  473. function swapElements(elm1, elm2) {
  474. var parent1, next1,
  475. parent2, next2;
  476. parent1 = elm1.parentNode;
  477. next1 = elm1.nextSibling;
  478. parent2 = elm2.parentNode;
  479. next2 = elm2.nextSibling;
  480. parent1.insertBefore(elm2, next1);
  481. parent2.insertBefore(elm1, next2);
  482. }
  483. // Swaps the positions of the presentation and the video
  484. function swapVideoPresentation() {
  485. var pop = Popcorn("#video");
  486. var wasPaused = pop.paused();
  487. var mainSectionChild = $("#main-section").children("[data-swap]");
  488. var sideSectionChild = $("#side-section").children("[data-swap]");
  489. swapElements(mainSectionChild[0], sideSectionChild[0]);
  490. resizeComponents();
  491. if (!wasPaused) {
  492. pop.play();
  493. }
  494. // hide the cursor so it doesn't appear in the wrong place (e.g. on top of the video)
  495. // if the cursor is currently being useful, he we'll be redrawn automatically soon
  496. showCursor(false);
  497. // wait for the svg with the slides to be fully loaded, then restore slides state and resize them
  498. function checkSVGLoaded() {
  499. var done = false;
  500. var svg = document.getElementsByTagName("object")[0];
  501. if (svg !== undefined && svg !== null && currentImage && svg.getSVGDocument('svgfile')) {
  502. var img = svg.getSVGDocument('svgfile').getElementById(currentImage.getAttribute("id"));
  503. if (img !== undefined && img !== null) {
  504. restoreSlidesState(img);
  505. done = true;
  506. }
  507. }
  508. if (!done) {
  509. setTimeout(checkSVGLoaded, 50);
  510. }
  511. }
  512. checkSVGLoaded();
  513. }
  514. function restoreSlidesState(img) {
  515. //set the current image as visible
  516. img.style.visibility = "visible";
  517. resizeSlides();
  518. restoreCanvas();
  519. var isPaused = Popcorn("#video").paused();
  520. if(isPaused) {
  521. restoreViewBoxSize();
  522. restoreCursor(img);
  523. }
  524. }
  525. function restoreCanvas() {
  526. var numCurrent = current_image.substr(5);
  527. var currentCanvas;
  528. if(svgobj.contentDocument) currentCanvas = svgobj.contentDocument.getElementById("canvas" + numCurrent);
  529. else currentCanvas = svgobj.getSVGDocument('svgfile').getElementById("canvas" + numCurrent);
  530. if(currentCanvas !== null) {
  531. currentCanvas.setAttribute("display", "");
  532. }
  533. }
  534. function restoreViewBoxSize() {
  535. var t = Popcorn("#video").currentTime().toFixed(1);
  536. var vboxVal = getViewboxAtTime(t);
  537. if(vboxVal !== undefined) {
  538. setViewBox(vboxVal);
  539. }
  540. }
  541. function restoreCursor(img) {
  542. var imageWidth = parseInt(img.getAttribute("width"), 10);
  543. var imageHeight = parseInt(img.getAttribute("height"), 10);
  544. showCursor(true);
  545. drawCursor(parseFloat(currentCursorVal[0]) / (imageWidth/2), parseFloat(currentCursorVal[1]) / (imageHeight/2), img);
  546. }
  547. // Manually resize some components we can't properly resize just using css.
  548. // Mostly the components in the side-section, that has more than one component that
  549. // need to fill 100% height.
  550. function resizeComponents() {
  551. var availableHeight = $("body").height();
  552. if (hasVideo) {
  553. availableHeight -= $("#video-area .acorn-controls").outerHeight(true);
  554. } else {
  555. availableHeight -= $("#audio-area .acorn-controls").outerHeight(true);
  556. }
  557. availableHeight -= $("#navbar").outerHeight(true); // navbar
  558. // portrait mode
  559. if (window.innerHeight > window.innerWidth) {
  560. var height = availableHeight * 0.6; // 60% for top bar
  561. $("#main-section").outerHeight(height);
  562. availableHeight -= height;
  563. $("#side-section").outerHeight(availableHeight);
  564. var chatHeight = availableHeight;
  565. $("#chat-area").innerHeight(chatHeight);
  566. } else {
  567. // $("#playback-row").outerHeight(availableHeight);
  568. $("#main-section").outerHeight(availableHeight);
  569. $("#side-section").outerHeight(availableHeight);
  570. var chatHeight = availableHeight;
  571. chatHeight -= $("#side-section").children("[data-swap]").outerHeight(true);
  572. $("#chat-area").innerHeight(chatHeight);
  573. }
  574. }
  575. // Need to resize the elements in a few occasions:
  576. // * Once the page and all assets are fully loaded
  577. // * When the page is resized
  578. // * When the video is fully loaded
  579. $(window).resize(function() {
  580. resizeComponents();
  581. });
  582. document.addEventListener("load", function() {
  583. resizeComponents();
  584. }, false);
  585. function checkVideoLoaded() {
  586. var video = $('#video')[0];
  587. if (video !== undefined && video !== null && video.readyState === 4) {
  588. resizeComponents();
  589. } else {
  590. setTimeout(checkVideoLoaded, 50);
  591. }
  592. }
  593. checkVideoLoaded();