Advertisement
Guest User

videos.js

a guest
Jan 23rd, 2017
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  Videos - odtwarzanie video w bloczku 'Wideo' na stronie głównej
  3.  
  4.  Założenia:
  5.  1. Player startuje gdy w vieporcie (z opóźnieniem po załadowaniu strony)
  6.  2. Player pauzuje gdy poza vieportem i użytkownik nie włączył głosu (gdy wejdzie w vieport to znowu odtwarzamy).
  7.  3. Player jest wyciszony na starcie
  8.  4. Materiał video jest początkowo w niższej jakości
  9.  5. Po włączeniu fullscreena zmieniamy jakość na HD
  10.  6. Gdy ktoś spauzuje film i wyjedzie z vieportu a następnie wróci to już mu nie startujemy video
  11.  
  12.  * @author Konrad Beśka
  13.  * @since 13.01.2017
  14.  */
  15.  
  16.  
  17. (function (w, doc) {
  18.     w.Inpl = w.Inpl || {};
  19.     w.console = w.console || {log: function () {}};
  20.  
  21.     if(w.Inpl.hasOwnProperty('videos')) {
  22.         console.log('Istnieje już [window.Inpl.videos]');
  23.         return;
  24.     }
  25.  
  26.     // konfiguracja videoplayera pochodzi z helpera php i renderowana jest w źródle strony do poniższej zmiennej
  27.     if (! w.playerVideosConfig){
  28.         console.log('Brak konfiguracji dla videonewsa, czyli brak [window.playerVideosConfig]');
  29.         return;
  30.     }
  31.     var config = w.playerVideosConfig;
  32.     var playlistData = w.playerVideosPlaylist;
  33.  
  34.     var workId = 0;
  35.     if (config.tracks && config.tracks[0] && config.tracks[0].data && config.tracks[0].data.id ){
  36.         workId = config.tracks[0].data.id;
  37.     } else {
  38.         console.log('Brak id materiału, czyli brak [window.playerVideosConfig.tracks[0].data.id]');
  39.         return;
  40.     }
  41.  
  42.  
  43.     // <FUNKCJE POMOCNICZE>
  44.  
  45.     // Manipulacja klasami css
  46.  
  47.     /**
  48.      * @param {Node} el - element DOM
  49.      * @param {String} name - nazwa klasy css
  50.      * @returns {boolean}
  51.      */
  52.     function hasClass(el, name) {
  53.         return (' ' + el.className + ' ').indexOf(' ' + name + ' ') > -1;
  54.     }
  55.  
  56.     /**
  57.      * @param {Node} el - element DOM
  58.      * @param {String} name - nazwa klasy css
  59.      * @returns {Node}
  60.      */
  61.     function addClass(el, name) {
  62.         if (!hasClass(el, name)) {
  63.             el.className += (el.className ? ' ' : '') + name;
  64.         }
  65.         return el;
  66.     }
  67.  
  68.     /**
  69.      * @param {Node} el - element DOM
  70.      * @param {String} name - nazwa klasy css
  71.      * @returns {Node}
  72.      */
  73.     function removeClass(el, name) {
  74.         var classList = ' ' + el.className + ' ';
  75.         while (classList.indexOf(' ' + name + ' ') > -1) {
  76.             classList = classList.replace(' ' + name + ' ', ' ');
  77.         }
  78.         el.className = typeof classList.trim === 'function' ? classList.trim() : classList.replace(/^\s+|\s+$/g, '');
  79.         return el;
  80.     }
  81.  
  82.  
  83.     /**
  84.      * Sprawdza czy podana zmienna jest tablicą
  85.      *
  86.      * @param variable
  87.      */
  88.     function isArray(variable) {
  89.  
  90.         if (Array.isArray) {
  91.             return Array.isArray(variable);
  92.         } else if( Object.prototype.toString.call(variable) === '[object Array]' ){
  93.             return true;
  94.         }
  95.  
  96.         return false;
  97.     }
  98.  
  99.     /**
  100.      * Tworzenie elementu DOM
  101.      *
  102.      * @param {String} tag - tag html, np. div
  103.      * @param {String} cssClass - klasa css - bez kropki, np. list-item-element
  104.      * @param {String} html - html do wstrzyknięcia do danego elementu
  105.      * @param {Object} attributes - obiekt z atrybutami html elementu np. {href: '/url'}
  106.      * @returns {Node}
  107.      */
  108.     function domEle(tag, cssClass, html, attributes) {
  109.         var el = document.createElement(tag);
  110.         if (typeof cssClass !== 'undefined' && cssClass !== null) {
  111.             el.className = cssClass;
  112.         }
  113.         if (typeof html !== 'undefined' && html !== null) {
  114.             el.innerHTML = html;
  115.         }
  116.  
  117.         if (typeof attributes === 'object') {
  118.             Object.keys(attributes).forEach(function (attr, index) {
  119.                 if (attributes.hasOwnProperty(attr)){
  120.                     el.setAttribute(attr, attributes[attr]);
  121.                 }
  122.             });
  123.         }
  124.  
  125.         return el;
  126.     }
  127.  
  128.     /**
  129.      * Dodajemy elementy Node DOM do innego Noda
  130.      * Wywodujemy w postaci addpend(rodzic, dziecko1, dziecko2..);
  131.      *
  132.      * @param container
  133.      * @param {Node|Array<Node>} childs
  134.      */
  135.     function append(container, childs) {
  136.         if (arguments.length > 2){
  137.             Array.prototype.forEach.call(arguments, function (ele, index) {
  138.                 if (index < 1 || ele === null){
  139.                     return;
  140.                 }
  141.  
  142.                 if(isArray(ele)){
  143.                     ele.forEach(function (el) {
  144.                         if (el === null){
  145.                             return;
  146.                         }
  147.  
  148.                         container.appendChild(el);
  149.                     })
  150.                 } else {
  151.                     container.appendChild(ele);
  152.                 }
  153.  
  154.             });
  155.         } else {
  156.             if (childs === null){
  157.                 return container;
  158.             }
  159.  
  160.             if(isArray(childs)){
  161.                 childs.forEach(function (el) {
  162.                     if (el === null){
  163.                         return;
  164.                     }
  165.                     container.appendChild(el);
  166.                 })
  167.             } else {
  168.                 container.appendChild(childs);
  169.             }
  170.  
  171.         }
  172.  
  173.         return container;
  174.     }
  175.  
  176.     /**
  177.      * Dodajemy listener na event dom
  178.      *
  179.      * @param {Node} node
  180.      * @param {string }eventName - nazwa zdarzenia
  181.      * @param {Function} callback
  182.      */
  183.     function event(node, eventName, callback) {
  184.         if (node.addEventListener) {
  185.             node.addEventListener(eventName, callback);
  186.         } else if (node.attachEvent) {
  187.             node.attachEvent('on' + eventName, callback);
  188.         }
  189.     }
  190.  
  191.     /**
  192.      * Limitowanie ilości wywołań
  193.      *
  194.      * @param {Function} fn - funkcja, którą chcemy opóźnić
  195.      * @param {Number} threshhold - czas odstępu wywołań w milisekundach
  196.      * @param {Object} scope - kontekst
  197.      * @returns {Function}
  198.      */
  199.     function throttle(fn, threshhold, scope) {
  200.         threshhold = threshhold && threshhold % 1 === 0 ? threshhold : 500;
  201.         var last,
  202.             timer;
  203.         return function () {
  204.             var context = scope || this;
  205.             var now = +new Date();
  206.             var args = arguments;
  207.  
  208.             if (last && now < last + threshhold) {
  209.                 clearTimeout(timer);
  210.                 timer = setTimeout(function () {
  211.                     last = now;
  212.                     fn.apply(context, args);
  213.                 }, threshhold);
  214.             } else {
  215.                 last = now;
  216.                 fn.apply(context, args);
  217.             }
  218.         };
  219.     }
  220.  
  221.     function toArray(obj) {
  222.         return Object.keys(obj).map( function (key) { return obj[key]; });
  223.     }
  224.  
  225.     // </FUNKCJE POMOCNICZE>
  226.  
  227.  
  228.  
  229.     w.Inpl.videos = {
  230.         pausedByUser: false, // Gdy ręcznie spauzuje to juz nie odtwarzamy go automatycznie (np. gdy ponownie wjechał do viewportu), aby wiedzieć czy ręcznie spauzowal - sprawdzamy event pause playera i czy jest w vieporcie - jezeli tak to znaczy ze to user spauzował
  231.         interactByUser: false,
  232.         videoHeight: 229,
  233.         place: null,
  234.         infoBlock: null, // warstwa pokazywana podczas pauzy i zakończenia video
  235.         header: null, // tytuł oraz logo
  236.         video: null,
  237.         linksArray: null,
  238.  
  239.         /**
  240.          * @returns {string}
  241.          */
  242.         getCookieName: function() {
  243.             return 'videos-id-' + this.getWorkId();
  244.         },
  245.  
  246.         getWorkId: function () {
  247.             return workId;
  248.         },
  249.  
  250.         isAutoplay: function () {
  251.             return true; //config.videonewsAutoplay || false;
  252.         },
  253.  
  254.         wasWatched: function () {
  255.             // w celu możliwości testowania, bez konieczności czyszczenia localstorage
  256.             if (config.videonewsTestVideonewsWorkId && config.videonewsTestVideonewsWorkId > 0 ) {
  257.                 return false;
  258.             }
  259.  
  260.             // sprawdzamy czy istnieje ciacho czyli czy już odtwarzał wcześniej - jeżeli tak to pomijamy
  261.             return Inpl.storage(this.getCookieName()) ? true : false;
  262.         },
  263.  
  264.         getVideoUrl: function () {
  265.             return null;
  266.         },
  267.  
  268.         getPosterUrl: function () {
  269.             return config.tracks[0].poster;
  270.         },
  271.  
  272.         getTitle: function () {
  273.             return config.tracks[0].data.title;
  274.         },
  275.  
  276.         getNthDataSrc: function (i) {
  277.             var images = doc.querySelectorAll('#videos li a.interia-tv img');
  278.             var dataSrcArray = []
  279.  
  280.             images.forEach( function( item, index ) {
  281.                 dataSrcArray[index] = item.getAttribute('data-src');
  282.             });
  283.  
  284.             return function () {
  285.                 return dataSrcArray[i]
  286.             };
  287.         },
  288.  
  289.         setWatched: function () {
  290.             var expire = new Date();
  291.             expire.setTime(expire.getTime() + 86400000);
  292.             Inpl.storage(this.getCookieName(), 1, {expires: expire});
  293.             //doc.cookie = this.getCookieName() + '=' + 1 + '; expires=' + expire.toGMTString();
  294.         },
  295.  
  296.         getPlace: function () {
  297.             if (this.place !== null){
  298.                 return this.place;
  299.             }
  300.  
  301.             return this.place = doc.getElementsByClassName('player-videos-wrapper')[0];
  302.         },
  303.  
  304.         /**
  305.          * Wyświetlamy planszę nad playerem
  306.          *
  307.          * @param {('pause'|'end')} type - typ planszy
  308.          */
  309.         showInfoBlock: function (type) {
  310.             var that = this;
  311.             var player = doc.getElementsByClassName('player-videos-wrapper')[0];
  312.  
  313.             if (this.infoBlock !== null){
  314.                 addClass(this.infoBlock, 'player-videonews__infoblock--visible');
  315.  
  316.                 removeClass(this.infoBlock, 'player-videonews__infoblock--pause');
  317.                 removeClass(this.infoBlock, 'player-videonews__infoblock--end');
  318.                 addClass(this.infoBlock, 'player-videonews__infoblock--' + type);
  319.                 return;
  320.             }
  321.  
  322.             //pierwszy raz - rendering
  323.  
  324.             var thumb;
  325.  
  326.             append(
  327.                 this.getPlace(),
  328.                 this.infoBlock = append(
  329.                     domEle('div', 'player-videonews__infoblock player-videonews__infoblock--visible player-videonews__infoblock--' + type),
  330.                     append(
  331.                         thumb = domEle('div', 'player-videonews__infoblock-thumb'),
  332.                         domEle('div', 'player-videonews__infoblock-thumb-ico'),
  333.                         domEle('img', 'player-videonews__infoblock-thumb-img', null, {src: that.getPosterUrl()})
  334.                     ),
  335.  
  336.                     append(
  337.                         domEle('div', 'player-videonews__infoblock-info'),
  338.                         domEle('h2', 'player-videonews__infoblock-title', that.getTitle()),
  339.                         domEle('a', 'player-videonews__infoblock-share', 'Udostępnij', {href: 'http://www.facebook.com/sharer/sharer.php?u=' + encodeURI(that.getVideoUrl()), target: '_blank'})
  340.                     )
  341.                 )
  342.             );
  343.  
  344.             // play i replay
  345.             event(thumb, 'click', function () {
  346.                 that.video.play();
  347.             });
  348.  
  349.         },
  350.         /**
  351.          * Ukrywamy planszę
  352.          */
  353.         hideInfoBlock: function () {
  354.             if (this.infoBlock !== null){
  355.                 removeClass(this.infoBlock, 'player-videonews__infoblock--visible');
  356.             }
  357.         },
  358.  
  359.         /**
  360.          * Renderujemy tytuł filmu i logo
  361.          * @param {String} title
  362.          */
  363.         renderHeader: function (title) {
  364.             append(
  365.                 this.getPlace(),
  366.                 this.header = append(
  367.                     domEle('div', 'player-videonews__header  player-videonews__header--visible'),
  368.                     domEle('div', 'player-videonews__title', title),
  369.                     domEle('img', 'player-videonews__logo', null, {src: '/i/videonews/logo.svg'})
  370.                 )
  371.             );
  372.         },
  373.  
  374.         getIwaConfig: function () {
  375.             return {
  376.                 attachment_id: this.video._attachmentId,
  377.                 title: this.video._attachmentTitle,
  378.                 origin: this.video._attachmentOrigin? this.video._attachmentOrigin : ''
  379.             }
  380.         },
  381.  
  382.         /**
  383.          *
  384.          * @param data
  385.          * @return {{}}
  386.          */
  387.         prepareTrackData: function (data) {
  388.             var preparedSrc = { lo: [], hi: [] };
  389.  
  390.             if ( data.src.hi[0].src ) { preparedSrc.hi.push( { type: 'video/mp4', src: data.src.hi[0].src } ); }
  391.             if ( data.src.lo[0].src ) { preparedSrc.lo.push( { type: 'video/mp4', src: data.src.lo[0].src } ); }
  392.  
  393.             return {
  394.                 title: data.data.title,
  395.                 src: preparedSrc,
  396.                 width: data.data.width,
  397.                 height: data.data.height,
  398.                 poster: data.data.poster,
  399.                 data: {
  400.                     title: data.data.title,
  401.                     id: data.data.id,
  402.                     desc: data.data.desc,
  403.                     url: data.data.url
  404.                 }
  405.             };
  406.         },
  407.  
  408.         addTracksToTracklist: function (trackList, tracksData) {
  409.             var trackData;
  410.             var i;
  411.  
  412.  
  413.             for (i = 1; i < 3; i += 1) {
  414.                 trackData = this.prepareTrackData(tracksData[i]);
  415.                 trackList.append(trackList.createTrackItem( trackData ));
  416.             }
  417.         },
  418.  
  419.         shiftLinks: function (linksArr) {
  420.             linksArr.unshift(linksArr.pop());
  421.             return linksArr;
  422.         },
  423.  
  424.         updateLinkElements: function (trackList, linksArray) {
  425.             var adAmount = 0;
  426.  
  427.             trackList.getAll().forEach( function( item, index ) {
  428.                 if (item._isAd) {
  429.                     adAmount += 1;
  430.                     return;
  431.                 }
  432.  
  433.                 index = adAmount ? index - adAmount : index;
  434.  
  435.                 linksArray[index].innerHTML = '';
  436.                 !hasClass(linksArray[index], 'player-videos-link') ? append(linksArray[index], domEle('img', 'lazy videos-img', item._data.title, {src: item._poster}), domEle('span', null, item._data.title)) : linksArray[index].innerHTML = item._data.title;;
  437.                 linksArray[index].href = item._data.url;
  438.  
  439.             } );
  440.         },
  441.  
  442.         rotateTracklist: function (trackList, linkElements) {
  443.             if (trackList.getCurrentTrack()._hasAd || !trackList || !linkElements) {
  444.                 return;
  445.             }
  446.             var that = this;
  447.  
  448.             if (!that.linksArray) {
  449.                 that.linksArray = toArray(linkElements);
  450.             }
  451.  
  452.             that.linksArray = that.shiftLinks(that.linksArray);
  453.  
  454.             that.updateLinkElements(trackList, that.linksArray);
  455.  
  456.         },
  457.  
  458.         getLinkElements: function () {
  459.             return doc.querySelectorAll('a.interia-tv');
  460.         },
  461.  
  462.         /**
  463.          * Akcja inicjująca
  464.          */
  465.         init: function () {
  466.             var that = this;
  467.  
  468.             // inicjalizacja playera.
  469.             /** @type {global.Inpl.Video.Player} */
  470.             var video = this.video = Inpl.Video.createInstance(config);
  471.             that.renderHeader(config.videonewsTitle);
  472.             var trackList = video.getTrackList();
  473.  
  474.  
  475.             that.addTracksToTracklist(trackList, playlistData);
  476.  
  477.  
  478.             // Logika odtwarzania video
  479.  
  480.             video.on('ended', function () {
  481.                 that.showInfoBlock('end');
  482.                 // jesli to ostatni element wideo ...
  483.                 if ( !trackList.isLastTrack() ) {
  484.                     video.nextAndPlay();
  485.                     that.rotateTracklist(trackList, that.getLinkElements());
  486.                 }
  487.             });
  488.  
  489.             video.on('pause', function () {
  490.                 if (checkVieport()){
  491.                     that.pausedByUser = true;
  492.                 }
  493.                 that.showInfoBlock('pause');
  494.             });
  495.  
  496.             video.on('play', function () {
  497.                 that.hideInfoBlock('pause');
  498.                 that.hideInfoBlock('end');
  499.             });
  500.  
  501.             video.one('play', function () {
  502.                 //that.setWatched();
  503.             });
  504.  
  505.             video.on('ready', function () {
  506.                 /** @type {global.Inpl.TrackItem} */
  507.                 var track = video.getCurrentTrack();
  508.                 track.curQuality('lo');
  509.                 this.trigger('changequality', track.curQuality());
  510.                 this._player.src( this.getTrackList().getCurrentTrack().getSrc() );
  511.                 video.muted(true);
  512.  
  513.                 // dopiero teraz nasłuchujemy na zmiany usera (bo wcześniejsze (powyższe) wyciszenie by nam się tutaj złapało)
  514.                 setTimeout(function () {
  515.                     var prevVolume = video.muted() ? 0 : video.volume();
  516.                     function logIwa(eventName) {
  517.                         iwa('stream', 'content', eventName, that.getIwaConfig());
  518.                     }
  519.                     // trigerujemy event mousemove, aby tooltip był widoczny (automatycznie znika co sekundę) - inaczej tego nie idzie zrobić w łatwy sposób..
  520.                     var tooltipTimer = setInterval(function () {
  521.                         window.vjs.trigger(video._player.controlBar.buttonsPanel.volumeChange.el_, 'mousemove');
  522.                     }, 1000);
  523.  
  524.                     video.on('volumechange', function () {
  525.                         that.interactByUser = true;
  526.                         if (!iwa){
  527.                             return;
  528.                         }
  529.  
  530.                         clearInterval(tooltipTimer);
  531.                         var currentVolume = video.volume();
  532.                         if (prevVolume == 0 && currentVolume > 0 ){
  533.                             logIwa('muteoff');
  534.                         } else if (prevVolume > 0 && currentVolume == 0 ){
  535.                             logIwa('muteon');
  536.                         }
  537.                         prevVolume = currentVolume;
  538.                     });
  539.                 }, 100);
  540.  
  541.                 if (that.isAutoplay()){
  542.                     monitorViewport();
  543.                     event(window, 'scroll', throttle(monitorViewport, 300));
  544.                 }
  545.             });
  546.  
  547.             video.on('fullscreenchange', function () {
  548.                 /** @type {global.Inpl.TrackItem} */
  549.                 var track = video.getCurrentTrack();
  550.  
  551.                 // zmieniamy jakość materiału na wysoką
  552.                 var currentQuality = track.curQuality();
  553.                 if (currentQuality !== 'hi'){
  554.                     track.curQuality('hi');
  555.                     this.trigger('changequality', track.curQuality());
  556.                     this._player.src( this.getTrackList().getCurrentTrack().getSrc() );
  557.                 }
  558.  
  559.                 //włączamy dźwięk
  560.                 video.muted(false);
  561.                 video.play();
  562.  
  563.                 if (this.isFullScreen() && iwa) {
  564.                     iwa('stream', 'content', 'fullscreen', that.getIwaConfig());
  565.                 }
  566.             });
  567.  
  568.             /**
  569.              * Sprawdza viewport i odpal player tylko gdy widoczny
  570.              * @returns {boolean} - czy w viewporcie
  571.              */
  572.             var monitorViewport = function () {
  573.  
  574.                 if (checkVieport()){
  575.                     // player widoczny dla uzytkownika więc gdy wcześniej ręcznie nie pauzował to go włączamy
  576.                     if (that.pausedByUser === false){
  577.                         video.play();
  578.                     }
  579.                 } else {
  580.                     if (that.pausedByUser === false && that.interactByUser === false){
  581.                         video.pause();
  582.                     }
  583.                 }
  584.             };
  585.  
  586.             var checkVieport = function () {
  587.                 var pos = videojs.findPosition(video.getContainer());
  588.                 var srollTop = typeof window.pageYOffset != 'undefined' ? window.pageYOffset: document.documentElement.scrollTop? document.documentElement.scrollTop: document.body.scrollTop? document.body.scrollTop:0;
  589.  
  590.                 if (srollTop + window.innerHeight - that.videoHeight/2 > pos.top && pos.top + that.videoHeight/2 > srollTop ){
  591.                     return true;
  592.                 } else {
  593.                     return false;
  594.                 }
  595.             };
  596.         }
  597.     };
  598.  
  599.     event(window, 'load', function () {
  600.         setTimeout(function () {
  601.             Inpl.videos.init();
  602.         }, 500);
  603.     });
  604.  
  605. })(window, document);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement