PageSourceSearch

http://hk.on.cc/module/player/h5player_uat.js

js on.cc collected 2026-09-24 08:40:19 UTC 183,685 bytes, 5,540 lines download raw bytes

1;(function() {
2    // helper function
3    var noop = function () { };
4
5    var domElem = {
6
7        find: function (selector) {
8
9            if (!selector) return;
10
11            var els = typeof selector === "string" ? this.querySelectorAll(selector) : [selector];
12
13            var r = Array.prototype.map.call(els, function(el) {
14                return extend(el, domElem);
15            });
16
17            return r.length == 1 ? r[0] : r.length ? r : undefined;
18
19        },
20
21        hasClass: function (className) {
22
23            var names = className.split(" ");
24            for (var i = 0; i < names.length; i++) {
25                var name = names[i];
26                var result = this.className.match(new RegExp('(\\s|^)' + name + '(\\s|$)')) ? true : false;
27                if ( result ) {
28                    return result;
29                }
30            }
31
32            return false;
33
34        },
35
36        addClass: function (className) {
37
38            className = Array.isArray(className) ? className : className.split(" ");
39
40            className.forEach(function (name) {
41
42                if (!this.hasClass(name)) {
43                    this.className = (this.className + " " + name).trim();
44                }
45
46            }.bind(this));
47
48            return this;
49
50        },
51
52        removeClass: function (className) {
53
54            className = Array.isArray(className) ? className : className.split(" ");
55
56            className.forEach(function (name) {
57
58                this.className = this.className.replace(new RegExp('(?:^|\\s)' + name + '(?!\\S)', 'g'), '');
59
60            }.bind(this));
61
62            return this;
63
64        },
65
66        toggleClass: function (className) {
67
68            className.split(" ").forEach(function (name) {
69
70                if (this.hasClass(name)) {
71                    this.removeClass(name);
72                }
73                else {
74                    this.addClass(name);
75                }
76
77            }.bind(this));
78
79            return this;
80
81        },
82
83        parent: function () {
84
85            var parent = this.parentElement;
86            return parent.hasOwnProperty("addClass") ? parent : extend(parent, domElem);
87
88        },
89
90        on: function (events, fn, useCapture) {
91
92            var _this = this;
93
94            useCapture = useCapture || false;
95
96            events.split(" ").forEach(function (v, k) {
97                getElemEvents(_this, v).push(fn);
98                _this.addEventListener(v, fn, useCapture);
99            });
100
101            return this;
102
103        },
104
105        off: function (events, fn, useCapture) {
106
107            var _this = this;
108
109            useCapture = useCapture || false;
110
111            if (!events) {
112
113                for (var name in _this._stnevEmelEmod) {
114                    domElem.off.call(_this, name, useCapture);
115                }
116
117            } else {
118
119                events.split(" ").forEach(function (evt, k) {
120
121                    var list = getElemEvents(_this, evt);
122
123                    if (fn) {
124                        _this.removeEventListener(evt, fn, useCapture);
125                        list.splice(list.indexOf(fn), 1);
126                    } else {
127                        list.forEach(function (_fn) {
128                            _this.removeEventListener(evt, _fn, useCapture);
129                        });
130                        getElemEvents(_this, evt, true);// clear all events
131                    }
132                });
133
134            }
135
136            return this;
137
138        },
139
140        once: function (events, fn, useCapture) {
141
142            var _this = this;
143
144            useCapture = useCapture || false;
145
146            events.split(" ").forEach(function (v, k) {
147                domElem.on.call(_this, v, function _fn(evt) {
148                    domElem.off.call(_this, v, _fn, useCapture);
149                    fn(evt);
150                }, useCapture);
151            });
152
153            return this;
154
155        },
156
157        prepend: function (val) {
158
159            if (typeof val == "string") {
160                this.insertAdjacentHTML("afterbegin", val);
161            }
162            else if( val instanceof Element ){
163                this.insertBefore(val, this.firstChild);
164            }
165
166            return this;
167
168        },
169
170        append: function (val) {
171
172            if (typeof val == "string") {
173                this.insertAdjacentHTML("beforeend", val);
174            }
175            else if( val instanceof Element ){
176                this.appendChild(val);
177            }
178
179            return this;
180
181        },
182
183        before: function (val) {
184
185            if (typeof val == "string") {
186                this.insertAdjacentHTML("beforebegin", val);
187            }
188            else if( val instanceof Element ){
189                this.parentElement.insertBefore(val, this);
190            }
191
192            return this;
193
194        },
195
196        after: function (val) {
197
198
199            if (typeof val == "string") {
200                this.insertAdjacentHTML("afterend", val);
201            }
202            else if( val instanceof Element ){
203                this.parentElement.insertBefore(val, this.nextSibling);
204            }
205
206            return this;
207
208        },
209
210        show: function () {
211            this.style.display = "block";
212            return this;
213        },
214
215        hide: function () {
216            this.style.display = "none";
217            return this;
218        },
219
220        fadeIn: function () {
221            this.style.visibility = "visible";
222            this.style.opacity = 1;
223            return this;
224        },
225
226        fadeOut: function () {
227            this.style.visibility = "hidden";
228            this.style.opacity = 0;
229            return this;
230        },
231
232        html: function (html) {
233
234            if (html) {
235                this.innerHTML = html;
236            }
237            else {
238                return this.innerHTML;
239            }
240
241            return this;
242
243        },
244
245        css: function (style, val) {
246
247            if (val) {
248                this.style[style] = val;
249            } else if (val === "") {
250                if (this.style.removeProperty) {
251                    this.style.removeProperty(style);
252                } else {
253                    this.style.removeAttribute(style);
254                }
255            } else if (typeof style == "object") {
256
257                for (var k in style) {
258                    this.style[[k]] = style[k];
259                }
260
261            }
262            else {
263                return window.getComputedStyle(this)[style];
264            }
265
266            return this;
267
268        }
269
270    };
271
272    var $ = domElem.find.bind(document);
273
274    var helper = /h5player_helper/i.test(window.location.href);
275
276    var text = {
277
278        autoplay: "自動播放",
279        cancel: "取消",
280        closeShare: "關閉分享",
281        copyFail: "複製失敗",
282        copySuccess: "複製成功",
283        copyURL: "複製影片網址",
284        copyURL2: "複製連結",
285        dateFormat: "mm月dd日 HH:MM",
286        dateFormat2: "yyyy年mm月dd日 HH:MM",
287        dayNames: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', '日', '一', '二', '三', '四', '五', '六'],
288        exitFullScreen: "結束全螢幕",
289        fullscreen: "全螢幕",
290        hideCtrlBar: "隱藏控制欄",
291        loop: "循環播放",
292        mute: "靜音",
293        newsLink: "新聞連結",
294        newsURL: "新聞連結",
295        nextUp: "即將播放",
296        normal: "正常",
297        notSupFullScreen: "全螢幕 ( 不支援 )",
298        notSupFullScreen2: "該瀏覽器不支援全螢幕功能",
299        ontv: "ONTV 東網電視",
300        prompt: "你的瀏覽器不支援此功能,影片連結:",
301        quality: "畫質",
302        replay: "重播",
303        setting: "設定",
304        share: "分享影片",
305        shareFrom: "分享自",
306        shwoCtrlBar: "顯示控制欄",
307        sina: "新浪微博",
308        skip: "略過廣告",
309        skip1: "廣告可在",
310        skip2: "秒後略過",
311        speed: "速度",
312        unmute: "解除靜音",
313        videoInfo: "影片資訊",
314        nicam_hk: "廣東話",
315        nicam_cn: "普通話"
316
317    };
318
319    var scriptLoadStarted = [];
320
321    var h5DefaultConfig = function() {
322
323        extend(this, {
324            
325            skipAdTime: 12,
326            timeOutForPlayNext: 10,
327            autoplay: false,
328            muted: false,
329            videoListRepeat: true,
330            disableShare : false,
331            disableSetting : false,
332            disablePlayNext: true,
333            disableOtherVideo: false,
334            disableRelatedNews: true,
335            themeColor: "#ff6600",
336            otherVideoOrder: ["related", "mostview", "group", "videolist"],
337            videoList: [],
338            xmlLoaded: noop,
339            xmlFailed: noop,
340            videoReady: noop,
341            onplay: noop,
342            onpause: noop,
343            onended: noop,
344            playNextCallBack: noop,
345            popUpCloseCallBack : noop,
346            enableVideoAd: {
347                preroll: false,
348                postroll: false,
349            },
350            
351            preload: true,
352            loadNext: true,
353    
354            otherVideoList: [],
355            otherVideoIdList: [],
356            otherVideoLoaded: false,
357    
358            qualities: [
359                {"level":0,"type":"iphone","pixel":"320p"},
360                {"level":1,"type":"ipad","pixel":"480p"}
361            ],
362
363            tracking: {},
364
365            hlsCallBacks: [],
366            adCompleteCallbacks: [],
367
368            lang: {}
369    
370        });
371
372    };
373
374    var log = (function () {
375
376        if (helper) {
377
378            if ( /h5player_helper_styleless/i.test(window.location.href) ) {
379                return console.log.bind(console);
380            } else {
381                return console.info.bind(console, '%c[h5Player]%c', 'color: #03A9F4;font-weight: bold', "");
382            }
383
384        } else {
385            return noop;
386        }
387
388    }());
389    
390    var defaultQualityLevel = 1;
391
392    var qualityType = ["iphone", "ipad", "hd"];
393    var qualityPixel = ["320p", "480p", "720p"];
394
395    function getQualityLevel(type) {
396        return qualityType.indexOf(type)
397    }
398
399    function getQualityPixel(level) {
400        return qualityPixel[level];
401    }
402
403    // remove polyfill for ie9
404    if (!('remove' in Element.prototype)) {
405        Element.prototype.remove = function () {
406            if (this.parentNode) {
407                this.parentNode.removeChild(this);
408            }
409        };
410    }
411
412    function removeAll(el) {
413
414        if (el) {
415            var els = Array.isArray(el) ? el : [el];
416            els.forEach(function (v) {
417                v.remove();
418            });
419        }
420
421    }
422
423    function extend(target, sources) {
424
425        target = target || this;
426
427        if (Object.assign) {
428            Object.assign(target, sources);
429        } else {
430            for (var i in sources) {
431                if (sources.hasOwnProperty(i)) {
432                    target[i] = sources[i];
433                }
434            }
435        }
436
437        return target;
438
439    }
440
441    // function getLoc(_loc){
442    //     return new RegExp(_loc).test(window.location.host) || new RegExp("/"+_loc+"/").test(window.location.pathname) ? _loc : false;
443    // }
444
445    function getElemEvents(el, name, clear) {
446
447        var extendName = "_stnevEmelEmod"; //"domElemEvents_" reverse;
448        var events     = el[extendName] = el[extendName] || {}; // bind event list to element
449
450        events[name] = (clear || !events[name]) ? [] : events[name];
451
452        return events[name];
453
454    }
455
456    function createElement(tagName, className) {
457        className = className || "";
458        return extend(document.createElement(tagName), domElem).addClass(className);
459    }
460
461    function each(_this, fn) {
462        Array.prototype.forEach.call(_this, fn);
463    }
464
465    function map(_this, fn) {
466        return Array.prototype.map.call(_this, fn);
467    }
468
469    function Num(str) {
470        return parseFloat(str);
471    }
472
473    function newTab(URL, videoElem, blur, focus) {
474
475        blur = blur || noop;
476        focus = focus || noop;
477
478        if (!videoElem) {
479            return;
480        }
481
482        var playing = videoElem instanceof Element || videoElem.playing();
483
484        window.addEventListener("focus", function onfocus(evt){
485            window.removeEventListener("focus", onfocus);
486            if (playing) {
487                videoElem.play();
488            }
489            focus();
490        })
491
492        blur();
493        videoElem.pause();
494
495        if (URL) {
496            var windowReference = window.open();
497            windowReference.location = URL;
498        }
499
500
501    }
502
503    function timeFormat(ms) {
504
505        if (isNaN(ms) || ms === Infinity) {
506            return;
507        }
508
509        var c = 0; // 0:00 ~ 9:59
510
511        if (ms >= 600 && ms < 3600) c = 1; // 10:00 ~ 59:59
512        else if (ms >= 3600 && ms < 36000) c = 3; // 1:00:00 ~ 9:59:59
513        else if (ms >= 36000) c = 4; // 10:00:00
514
515        return new Date(ms * 1000).toISOString().substr(15 - c, 4 + c);
516
517    }
518
519    function xmlTextParse(str) {
520
521        str = str || "";
522        str = typeof str === "string" ? str : str.textContent;
523
524        return str.trim().replace(/\\<\!\[CDATA\[|\]\]\>/g, '');
525
526    }
527
528    function filterXMLData(xml) {
529
530        function textContent(selector) {
531            return xml.querySelector(selector).textContent.trim();
532        }
533        
534        // main category in ontv
535        var category = ['3', '4', '2', '260', '262', '5', '241', '246'];
536        var group = "3";
537        var groups = map(xml.querySelectorAll("groupList group"), function (tag) {
538    
539            var _group = tag.textContent.trim();
540            if (category.indexOf(_group) !== -1) {
541                group = _group;
542            }
543    
544            return [_group, tag.getAttribute("text")];
545    
546        });
547
548        var qualities = Array.prototype.reduce.call(xml.querySelectorAll("availableFormat url"), function(filtered, tag) {
549
550            if ( /\.mp4/.test(tag.textContent.trim()) ) {
551                var type = tag.textContent.trim().replace(/^.*_|\..*[a-zA-Z0-9]/g, '');
552                var level = getQualityLevel(type);
553                filtered.push({
554                    level: level,
555                    type: type,
556                    pixel: getQualityPixel(level)
557                });
558            }
559
560            return filtered;
561
562        }, []).sort(function(a, b){
563            return a.level - b.level;
564        })
565        
566        var quality = defaultQualityLevel;
567        var updateTime = textContent('updateTime');
568        var videoId = textContent('programId');
569        var createTime = textContent('createTime');
570        var videoDate = h5Player.fn.dateFormat(new Date(createTime * 1000), 'yyyymm');
571        var posterName = textContent("thumbnailUrlList url").replace(/^.*[\\\/]/g, '');
572        var poster = 'http://tv.on.cc/xml/Thumbnail/' + videoDate + '/bigthumbnail/' + posterName + '?t=' + updateTime;
573        var src = 'http://video.cdn.on.cc/Video/' + videoDate + '/' + videoId + '_' + qualities[quality].type + '.mp4?t=' + updateTime;
574    
575        return {
576            
577            src:         src,
578            group:       group,
579            groups:      groups,
580            poster:      poster,
581            posterName:  posterName,
582            updateTime:  updateTime,
583            createTime:  createTime,
584            videoId:     videoId,
585            quality:     quality,
586            qualities:   qualities,
587            keyword:     textContent('keyword'), //first keyword
588            duration:    textContent("duration"),
589            title:       xmlTextParse(xml.querySelector('title')),
590            description: xmlTextParse(xml.querySelector('description')),
591            keywords:    map(xml.querySelectorAll('keyword'), function (tag) {
592                            return [tag.getAttribute("text"), tag.textContent];
593                         }),
594            news:        map(xml.querySelectorAll("news_url"), function (tag) {
595                            var url = tag.textContent.trim(),
596                                id  = url.replace(/^.*[\\\/]|\..*[a-zA-Z0-9]/g, '');
597                            return {
598                                url: url,
599                                articleId: id,
600                                title: tag.getAttribute("title")
601                            };
602                        })
603            
604        };
605
606    }
607
608    function define(key, getter, setter, target) {
609        target = target || this;
610        Object.defineProperty(target, key, {
611            enumerable: true,
612            configurable: true,
613            get : getter,
614            set : setter,
615        });
616    }
617    
618    function defineProperties(player) {
619        
620        var _define = define.bind(player);
621        var video = player.video;
622        var support = player.h5playerAvailable;
623        var thumbnailDom = player.container.find(".h5Thumbnail");
624        var thumbnail = thumbnailDom
625                .on("error", domElem.hide)
626                .on("load", function load() {
627                    if (video.paused && !video.seeking) {
628                        this.show();
629                    } else this.hide();
630                });
631        
632        var qualityLevel = defaultQualityLevel;     
633                
634        _define('thumbnail', function(){
635            return support ? thumbnail.src : video.poster;
636        }, function(newValue){
637
638            newValue = newValue || "";
639
640            if (!newValue) {
641                thumbnailDom.hide();
642            }
643
644            if (support) {
645                if ( thumbnail.src != newValue ) {
646                    thumbnail.src = newValue;
647                }
648            } else {
649                if ( video.poster != newValue ) {
650                    video.poster = newValue;
651                }
652            }
653            
654        });
655        
656        _define("volume", function() {
657            return video.volume;
658        }, function(newValue){
659            video.volume = newValue;
660        });
661        
662        _define("muted", function() {
663            return video.muted;
664        }, function(newValue){
665            video.muted = newValue;
666        });
667        
668        _define("playbackRate", function() {
669            return video.playbackRate;
670        }, function(newValue){
671            video.playbackRate = newValue;
672        });
673
674        _define("quality", function() {
675            return player.qualities[qualityLevel] || {};
676        }, function(newValue){
677
678            if ( newValue !== undefined && newValue !== null ) {
679
680                if ( isNaN(newValue) ) {
681                    console.warn("quality input is " + newValue + ", it should be Number");
682                }
683
684                qualityLevel = newValue;
685                
686
687            }
688            
689        });
690
691        var currLang = h5Player.fn.getCookie("h5Nicam") || "HK";
692        _define("currLang", function () {
693            return this.lang[currLang];
694        }, function setter(newValue) {
695            if (newValue !== undefined && newValue !== null) {
696                currLang = newValue;
697                h5Player.fn.setCookie("h5Nicam", newValue);
698            }
699        });
700    
701    }
702
703    function isSameVideo(obj1, obj2) {
704        return (obj1[1] || obj1.videoId) === (obj2[1] || obj2.videoId) &&
705                (obj1[0] || obj1.createTime === (obj2[0] || obj2.createTime))
706    }
707
708    function updateVideoListIndex(player, target) {
709        var list = player.videoList;              
710        if (list.length) {
711            var index = list.indexOf(target);
712            if ( index !== -1 ) {
713                player.videoListIndex = index;
714            } else {
715                for( var i=0; i<list.length; i++) {
716                    if ( isSameVideo(target, list[i]) ) {
717                        player.videoListIndex = i;
718                        break;
719                    }
720                }
721            }
722        }
723    }
724
725    /*
726
727        to fix:
728
729        to test:
730            - mutiple player video tracking
731
732    */
733
734    function h5Player(config) {
735
736        this.config = {};
737
738        extend(this.config, this.commonConfig);
739        extend(this.config, config || {});
740
741        [new h5DefaultConfig(), this.fn.platform(), this.config].forEach(extend.bind(this, null));
742        
743        var _this = this;
744        var container = this.container = $(this.container) || createElement("div");
745        var video = this.video = container.find("video") || createElement("video");
746        var containerClassName = [
747                "h5PlayerCtn",
748                "h5Loading",
749                "h5Paused",
750                helper ? "h5Helper" : "",
751                this.live ? "h5Live" : "",
752                this.mobile ? "h5Mobile" : "",
753                this.touchable ? "h5Touchable" : "",
754                this.IE9 ? "h5RubbishIE9" : "",
755                this.cssSupport.objectfit ? "h5Ojectfit" : ""
756            ];
757        
758        video.setAttribute('playsinline', 'true');
759        
760        if (this.h5playerAvailable === undefined) {
761            this.h5playerAvailable = video.playsInline || !this.iPhone;
762        }
763        
764        this.titleContainer = ($(this.titleContainer) || createElement("div", "h5VideoTitle"));
765        
766        video.addClass("h5MediaPlayer h5RatioChild");
767        container.addClass( containerClassName )
768            .append(
769                    '<div class="tracking"></div>'
770                +   '<div class="h5MediaParent h5Ratio-16-9 h5RatioParent"></div>'
771                +   '<div class="h5LoadingLayer h5AbsLayer h5Transparent"><div class="h5AbsLayer"></div></div>'
772            ).find(".h5RatioParent")
773                .append(video)
774                .append('<img class="h5Thumbnail h5RatioChild">');
775        
776        defineProperties(this);
777
778        if (this.videoList.length) {
779
780            var index = this.startIndex || 0,
781                curr  = this.videoList[index];
782
783            this.videoId        = curr[1] || curr.videoId;
784            this.createTime     = curr[0] || curr.createTime;
785            this.videoListIndex = index;
786
787            if (this.videoList.length > 1) {
788                this.disablePlayNext = false;
789            }
790
791        }
792
793        (function _init() {
794
795            if (_this.big5 && !h5Player.prototype._big5) {
796                _this.fn.loadScript("http://hk.on.cc/module/player/h5player-big5.js", _init);
797                return;
798            }
799            
800            var lang = _this.currLang;
801            if ( lang ) {
802
803                _this.videoId = lang.vid;
804                _this.createTime = lang.vcreateTime;
805
806            } else if ( /-nicam/.test(_this.videoId) ) {
807
808                    h5Player.fn.ajax({
809                        url: "http://datafeed.on.cc/videoLangMapping/byVid?vid=" + _this.videoId + "&createTime=" + _this.createTime,
810                        dataType: "json",
811                        success: function(data) {
812                            _this.lang = data;
813                            _init();
814                        },
815                        fail: function() {
816                            log("nicam mapping feed fail, try to reload");
817                            setTimeout(_init, 3000);
818                        }
819                    });
820                    
821                 return;               
822
823            }
824
825            text = h5Player.prototype._big5 || text;
826
827            if ((_this.createTime && _this.videoId) || _this.xmlURL) {
828            
829                _this.fn.loadXML(_this.xmlURL || _this, function (xml) {
830                    
831                    extend(_this, filterXMLData(xml));
832
833                    _this.xmlLoaded.call(_this);
834
835                    if ( _this.usem3u8 && _this.qualities.length > 2 ) {
836                        _this.src = _this.src.replace(/_.[ipad|iphone|hd]*.\.mp4/, ".m3u8");
837                        _this.qualities = [];
838                    }
839
840                    if ( _this.preload !== false ) {
841                        _this.setVideoSrc(_this, _this.init.bind(_this));
842                    }
843                    
844                }, function(){
845                    log("loading xml failed")
846                    _this.xmlFailed.call(_this);
847                });
848                
849            } else if ( _this.live ){
850                _this.setVideoSrc(_this, _this.init.bind(_this))
851            } else {
852                _this.init();
853            }
854
855        }());
856
857    }
858
859    h5Player.prototype = {
860
861        init: function () {
862
863            var video  = this.video,
864                config = this.config;
865
866            this.thumbnail = this.poster;
867            this.titleContainer.textContent = this.title || "";
868
869            if (this.h5playerAvailable) {
870
871                video.controls = false;                
872                
873                if (typeof this.enableVideoAd !== "object" || this.enableVideoAd === null) {
874
875                    this.enableVideoAd = {
876                        preroll: this.enableVideoAd ? true : false,
877                        postroll: false
878                    };
879
880                }
881
882                if ( this.mobile && !this.wifi ) {
883                    // disable autoplay in mobile device, if no wifi connnection detected
884                    this.autoplay = false;
885                }
886
887                this.setUpControls();
888                this.addListener();
889                this.relatedNews();
890                this.nicam.init.call(this);
891                this.setting.init.call(this);
892                this.contextMenu.init.call(this);
893                this.miniPlayer.init.call(this);
894                this.share.init.call(this);
895
896                this.videoAd.init.call(this);
897
898                this.volume = "volume" in config 
899                    ? config.volume
900                    : this.fn.getCookie("h5Volume") || this.volume;
901
902                this.muted = "muted" in config 
903                    ? config.muted
904                    : JSON.parse(this.fn.getCookie("h5mute") || this.muted);
905
906
907            } else {
908                this.container.removeClass("h5Paused h5Loading");
909                this.addIOSListener();
910            }
911
912        },
913
914        setUpControls: function () {
915
916            var ctn = this.container;
917            var loadingLayer = ctn.find(".h5LoadingLayer");
918
919            if (ctn.find(".h5ControlsBar")) {
920                return;
921            }
922
923            loadingLayer.before('<div class="h5PlayPauseLayer h5AbsLayer h5Transparent"></div>');
924
925            ctn.append(
926
927                '<div class="h5ShareLayer h5AbsLayer"></div>' +
928
929                '<div class="h5ControlsBar">' +
930
931                    '<div class="h5floatBoxCtn">' +
932                        '<div class="h5Txt h5Times"></div>' +
933                        '<div class="h5Txt h5RepalyTxt">' + text.replay + '</div>' +
934                        '<div class="h5Txt h5VolumeTxt">' + text.mute + '</div>' +
935                        '<div class="h5Txt h5NewsTxt">' + text.newsURL + '</div>' +
936                        '<div class="h5Txt h5ShareTxt">' + text.share + '</div>' +
937                        '<div class="h5Txt h5SettingTxt">' + text.setting + '</div>' +
938                        '<div class="h5Txt h5FullScreenTxt">' + text.fullscreen + '</div>' +
939                    '</div>' + // h5floatBoxCtn end
940
941                    '<div class="h5ProgressBarCtn">' +
942                        '<div class="h5Bar h5BgBar"></div>' +
943                        '<div class="h5Bar h5LoadingBar"></div>' +
944                        '<div class="h5Bar h5HoverBar"></div>' +
945                        '<div class="h5Dot" style="background-color:' + this.themeColor + '"></div>' +
946                        '<div class="h5Bar h5ProgressBar" style="background-color:' + this.themeColor + '"></div>' +
947                    '</div>' + // h5ProgressBarCtn end
948
949                    '<div class="h5ButtonCtn">' +
950
951                        '<div class="h5LeftSide">' +
952                            '<div class="h5PlayPause h5Btn">' + this.svg.playIcon.html.call(this) + '</div>' +
953                            '<div class="h5VolumeControls high" >' +
954                                '<div class="h5VolumeBtn h5Btn">' + this.svg.get.call(this, "high") + '</div>' +
955                                '<div class="h5VolumeCtonrolsBar">' +
956                                    '<div class="h5Bar h5BgBar"></div>' +
957                                    '<div class="h5Bar h5Volume"></div>' +
958                                    '<div class="h5Dot h5VolDot"></div>' +
959                                '</div>' + // h5VolumeCtonrolsBar end
960                            '</div>' + // h5VolumeControls end
961
962                            '<div class="h5VideoTime">' +
963                                '<div class="h5CurrentTime">0:00</div>' +
964                                '<div class="slash">/</div>' +
965                                '<div class="h5Duration">' + (timeFormat(this.duration) || "") + '</div>' +
966                            '</div>' + // h5VideoTime end
967                        '</div>' + // h5LeftSide end
968
969                        '<div class="h5RightSide">' +
970                            '<div class="h5Nicam h5Btn h5Table">'+
971                                '<div class="h5Cell">'+
972                                    '<div rel="HK">'+ text.nicam_hk +'</div>' +
973                                    '<div rel="CN">'+ text.nicam_cn +'</div>' +
974                                '</div>' +
975                            '</div>' +
976                            '<div class="h5ToggleNews h5Btn">' + this.svg.get.call(this, "news") + '</div>' +
977                            '<div class="h5ToggleShare h5Btn">' + this.svg.get.call(this, "share") + '</div>' +
978                            '<div class="h5ToggleSetting h5Btn">' + this.svg.get.call(this, "setting") + '</div>' +
979                            '<div class="h5ToggleFullScreenBtn h5Btn">' + this.svg.get.call(this, "fullscreen") + '</div>' +
980                        '</div>' + // h5RightSide end
981                    '</div>' + // h5ButtonCtn end
982
983                '</div>
983' + // h5ControlsBar end
984
985                '<div class="h5SettingPlane h5FloatOnCtrlBar"></div>' +
986
987                '<div class="h5ContextMenu"></div>' +
988                '<div class="h5VideoLinkVal"><textarea type="text" val=""></textarea></div>'
989            );
990
991            if (this.titleContainer.hasClass("h5VideoTitle")) {
992                loadingLayer.before(this.titleContainer);
993            }
994
995        },
996
997        addListener: function () {
998
999            var _this    = this,
1000                ctn      = this.container,
1001                video    = this.video,
1002                videoAd  = this.videoAd,
1003                playing  = false,
1004                playIcon = this.svg.playIcon.set.bind(this),
1005                times    = ctn.find(".h5Times"),
1006                hoverBar = ctn.find(".h5HoverBar"),
1007                loadingBar = ctn.find(".h5LoadingBar"),
1008                hideControlTimeOut;
1009            var thumbnail = ctn.find(".h5Thumbnail");    
1010
1011            var progressBar = {
1012
1013                dom: ctn.find(".h5ProgressBarCtn"),
1014                dot: ctn.find(".h5ProgressBarCtn .h5Dot"),
1015                status: {
1016                    drag: false,
1017                    down: false,
1018                },
1019                up: function (evt) {
1020
1021                    progressBar.status.drag = false;
1022                    progressBar.status.down = false;
1023
1024                    if (video.ended) {
1025                        videoEvent.ended(evt);
1026                    }
1027                    else if (playing) {
1028                        playing = false;
1029                        _this.play();
1030                    }
1031
1032                    timesFloatBoxEvent(evt);
1033
1034                    times.fadeOut();
1035                    hoverBar.hide();
1036
1037                    ctn.removeClass("h5KeepCtrl");
1038                    progressBar.dom.removeClass("hover");
1039                    domElem.removeClass.call(document.body, "h5DisablePointerEvt");
1040                    domElem.off.call(window, "mouseup touchend", progressBar.up);
1041                    domElem.off.call(window, "mousemove touchmove", progressBar.drag);
1042
1043                },
1044                down: function (evt) {
1045
1046                    checkIfControlBarVisible(function () {
1047
1048                        if (_this.adPlaying()) {
1049                            return;
1050                        }
1051
1052                        if (_this.adReady && _this.enableVideoAd.preroll && !_this.adCompleted) {
1053                            _this.play();
1054                            return;
1055                        }
1056
1057                        clearTimeout(hideControlTimeOut);
1058
1059                        thumbnail.hide();
1060
1061                        progressBar.status.down = true;
1062                        progressBar.dom.addClass("hover");
1063
1064                        domElem.on.call(window, "mousemove touchmove", progressBar.drag);
1065                        domElem.on.call(window, "mouseup touchend", progressBar.up);
1066
1067                        playing = video.paused && !_this.ended() ? false : true;
1068
1069                        progressBar.drag(evt);
1070
1071                        timesFloatBoxEvent(evt);
1072
1073                        ctn.addClass("h5KeepCtrl");
1074
1075                        document.body.className += " h5DisablePointerEvt";
1076
1077                    })();
1078
1079                },
1080                leave: function (evt) {
1081
1082                    if (!progressBar.dom.hasClass("hover")) {
1083                        domElem.off.call(window, "mousemove touchmove", timesFloatBoxEvent);
1084                        times.fadeOut();
1085                        hoverBar.hide();
1086                    }
1087
1088                },
1089                drag: function (evt) {
1090
1091                    var start = progressBar.dom.getBoundingClientRect().left,
1092                        max   = progressBar.dom.clientWidth,
1093                        x     = pos(evt).x,
1094                        input = {};
1095
1096                    if (!_this.adPlaying()) {
1097
1098                        evt.preventDefault();
1099
1100                        progressBar.status.drag = true;
1101
1102                        input.pct = Math.max(0, Math.min(max, x - start)) / max;
1103
1104                        if (!video.seeking) {
1105                            _this.pause();
1106                        }
1107
1108                        function update() {
1109                            video.currentTime = input.curr = input.pct * video.duration;
1110                        }
1111
1112                        try {
1113                            update();
1114                        } catch(e) {
1115                            _this.load(update);
1116                        }
1117
1118                        if (!_this.ended()) {
1119                            playIcon("play");
1120                        }
1121
1122                        thumbnail.hide();
1123
1124                        _this.updateProgressBar(input);
1125
1126                        timesFloatBoxEvent(evt);
1127
1128                    }
1129
1130                }
1131
1132            };
1133
1134            var volumeBar = {
1135
1136                dom: ctn.find(".h5VolumeCtonrolsBar"),
1137                dot: ctn.find(".h5VolDot"),
1138                down: function (evt) {
1139                    volumeBar.move(evt);
1140                    ctn.addClass("h5KeepCtrl");
1141                    domElem.on.call(window, "mouseup touchend", volumeBar.up);
1142                    domElem.on.call(window, "mousemove touchmove", volumeBar.move);
1143                },
1144                move: function (evt) {
1145
1146                    var max    = volumeBar.dom.clientWidth,
1147                        start  = volumeBar.dom.getBoundingClientRect().left,
1148                        x      = pos(evt).x,
1149                        volume = Math.max(0, Math.min(max, x - start)) / max;
1150
1151                    volumeBar.dom.parent().addClass("hover");
1152
1153                    _this.muted  = false;
1154                    _this.volume = volume;
1155
1156                },
1157                up: function (evt) {
1158                    ctn.removeClass("h5KeepCtrl");
1159                    domElem.off.call(window, "mouseup touchend", volumeBar.up);
1160                    domElem.off.call(window, "mousemove touchmove", volumeBar.move);
1161                }
1162
1163            };
1164
1165            var videoEvent = {
1166
1167                play: function () {
1168
1169                    if (document.querySelectorAll(".h5PlayerCtn").length > 1) {
1170                        _this.volume = _this.fn.getCookie("h5Volume") || _this.volume;
1171                        _this.muted = JSON.parse(_this.fn.getCookie("h5mute") || _this.muted);
1172                    }
1173
1174                    thumbnail.hide();
1175
1176                },
1177
1178                playing: function (evt) {
1179
1180                    if (_this.enableVideoAd.preroll && !_this.adCompleted) {
1181                        return;
1182                    }
1183
1184                    playIcon("pause");
1185
1186                    ctn.removeClass("h5Loading");
1187
1188                },
1189
1190                timeupdate: function (evt) {
1191
1192                    _this.updateProgressBar({
1193                        curr: video.currentTime,
1194                        total: video.duration
1195                    });
1196
1197                    updateLoadingBar(evt);
1198
1199                },
1200
1201                "waiting seeking": function (evt) {
1202                    if (!_this.ended() && !progressBar.dom.hasClass("hover")) {
1203                        ctn.addClass("h5Loading");
1204                    }
1205                },
1206
1207                seeked: function (evt) {
1208                    ctn.removeClass("h5Loading");
1209                },
1210
1211                ended: function (evt) {
1212
1213                    if (ctn.hasClass("h5Ended") || _this.adPlaying() || progressBar.status.down) {
1214                        return;
1215                    }
1216
1217                    log("video ended");
1218
1219                    playIcon("replay");
1220
1221                    ctn.removeClass("h5HideCtrl h5Loading");
1222
1223                    if (_this.enableVideoAd.postroll && !_this.postrollAdLoaded) {
1224                        _this.postrollAdLoaded = true;
1225                        videoAd.init.call(_this, "postroll");
1226                    } else {
1227                        _this.playNext.init.call(_this);
1228                    }
1229
1230                    _this.onended.call(_this);
1231
1232                },
1233
1234                volumechange: function () {
1235
1236                    var vol       = this.muted ? 0 : this.volume;
1237                    var volSatate = this.muted ? "off" : vol === 0 ? "muted": vol < 0.5 ? "low": "high";
1238                    var left      = ctn.hasClass("h5FullScreen") ? ["22px", "34px"]: ["16px", "30px"];
1239                    var volDot    = ctn.find(".h5VolDot");
1240                    var stickyAd  = videoAd.stickyAds.adsComponent;
1241                    var googleAd  = videoAd.googleAd.adsManager;
1242                    var itvcVideo = ctn.find(".h5ItvcContainer video");
1243                    var _text     = this.muted ? text.unmute : text.mute;
1244                    var width     = 52;
1245                
1246                    ctn.find(".h5VolumeTxt")
1247                        .css("left", this.muted ? left[0] : left[1])
1248                        .html(_text);
1249                
1250                    ctn.find(".h5Volume").style.width = vol * width + "px";
1251                    ctn.find(".h5ContextMenu .h5ToggleMute").innerHTML = _text;
1252                    ctn.find(".h5VolumeBtn").innerHTML = _this.svg.get.call(_this, volSatate);
1253                
1254                    volDot.style.left = "calc(" + vol * 100 + "% - " + Num(volDot.css("width")) / 2 + "px)";
1255                
1256                    if (stickyAd) {
1257                        stickyAd.onVolumeLevelChanged(vol);
1258                    }
1259                    if (googleAd) {
1260                        googleAd.setVolume(vol);
1261                    }
1262
1263                    if (itvcVideo) {
1264                        itvcVideo.volume = vol;
1265                        itvcVideo.muted = _this.muted;
1266                    }
1267
1268                    // _this.setVolume();
1269                    _this.fn.setCookie("h5Volume", this.volume);
1270                    _this.fn.setCookie("h5mute", JSON.stringify(this.muted));
1271                },
1272
1273                durationchange: function(){
1274                    _this.duration = this.duration;
1275                    ctn.querySelector(".h5Duration").innerHTML = timeFormat(this.duration);
1276                },
1277
1278                pause: playIcon.bind(_this, "play"),
1279
1280                progress: updateLoadingBar
1281
1282            };
1283            
1284            function pos(evt) {
1285                return {
1286                    x : evt.changedTouches ? evt.changedTouches[0].pageX : evt.pageX,
1287                    y : evt.changedTouches ? evt.changedTouches[0].pageY : evt.pageY
1288                };
1289            }
1290
1291            function timesFloatBoxEvent(evt) {
1292
1293                if (_this.adPlaying()) {
1294                    times.fadeOut();
1295                    hoverBar.hide();
1296                    return;
1297                }
1298
1299                var max   = progressBar.dom.clientWidth,
1300                    width = times.clientWidth,
1301                    x     = pos(evt).x,
1302                    left  = x - progressBar.dom.getBoundingClientRect().left;
1303
1304                // console.log(paddingLeft)
1305                if (times) {
1306
1307                    times
1308                        .fadeIn()
1309                        .html(timeFormat(Math.max(0, Math.min(max, left)) / max * _this.duration) || "");
1310
1311                    if (width) {
1312                        times.css("left", Math.max(0, Math.min(max - width, left - width / 2)) + "px");
1313                    }
1314
1315                }
1316
1317                if ( hoverBar ) {
1318                    hoverBar.show()
1319                    if (width) {
1320                        hoverBar.style.width = Math.min(1, left / max) * 100 + "%";
1321                    }
1322                }
1323
1324            }
1325
1326            function checkIfControlBarVisible(fn) {
1327                return function() {
1328                    if (ctn.find('.h5ControlsBar').css("opacity") === "1" || !_this.mobile) {
1329                        fn.call(_this);
1330                    }
1331                }
1332            }
1333
1334            function updateLoadingBar(evt) {
1335                
1336                var buffered = video.buffered;
1337                if ( buffered.length ) {
1338                    loadingBar.style.width = (  buffered.end(buffered.length-1) / video.duration * 100  )+ "%";
1339                }
1340            }
1341
1342            for (var name in videoEvent) {
1343                video.on(name, videoEvent[name]);
1344            }
1345
1346            ctn.on("contextmenu", function (evt) {
1347
1348                    evt.preventDefault();
1349
1350                    var menu = ctn.find(".h5ContextMenu");
1351                    
1352                    if (!_this.adPlaying() && evt.target === ctn.querySelector(".h5PlayPauseLayer") ) {
1353
1354                        ctn.addClass("h5ContextMenuOn");
1355
1356                        menu.style.left = evt.clientX + "px";
1357                        menu.style.top = evt.clientY + "px";
1358
1359                    }
1360
1361                })
1362                .on("mousemove touchmove", function (evt) {
1363
1364                    clearTimeout(hideControlTimeOut);
1365
1366                    ctn.removeClass("h5HideCtrl");
1367
1368                    hideControlTimeOut = setTimeout(function () {
1369                        if (
1370                            (!ctn.hasClass("h5ShareOn h5Paused h5Ended h5KeepCtrl h5Loading") || _this.adPlaying()) && 
1371                            (!ctn.find(".h5ControlsBar:hover") || _this.mobile) &&
1372                            !(_this.adPlaying() && _this.mobile) && // video ad in mobile always keep the control bar 
1373                            !progressBar.dom.hasClass("hover") 
1374                        ) {
1375                            ctn.addClass("h5HideCtrl");
1376                        }
1377                    }, 2000);
1378
1379                })
1380                
1381
1382            progressBar.dom
1383                .on("mousedown touchstart", progressBar.down)
1384                .on("mouseleave touchend", progressBar.leave)
1385                .on("mousemove touchmove", timesFloatBoxEvent);
1386
1387            volumeBar.dom.on("mousedown", volumeBar.down);
1388
1389            ctn.find(".h5VolumeBtn").on("click", checkIfControlBarVisible(_this.toggleMute));
1390
1391            ctn.find(".h5ToggleShare").on("click", checkIfControlBarVisible(_this.toggleShare));
1392
1393            ctn.find(".h5PlayPause").on("click", checkIfControlBarVisible(_this.togglePlayPause));
1394
1395            ctn.find(".h5PlayPauseLayer").on("click", checkIfControlBarVisible(_this.togglePlayPause));
1396
1397            ctn.find(".h5ToggleFullScreenBtn").on("click", checkIfControlBarVisible(_this.toggleFullScreen));
1398
1399            ctn.find(".h5ToggleSetting").on("click", checkIfControlBarVisible(function () {
1400                ctn.toggleClass("h5SettingOn");
1401                if (ctn.find(".h5SettingPlane").hasClass("speed quality")) {
1402                    _this.setting.changeOption.call(_this);
1403                }
1404            }));
1405
1406            ctn.find(".h5ButtonCtn .h5Btn").forEach(function (btn) {
1407                btn.on("mouseenter mouseleave", function (evt) {
1408
1409                    var elem = evt.currentTarget,
1410                        leave = /leave/.test(evt.type),
1411                        target;
1412
1413                    if (domElem.hasClass.call(elem, "h5PlayPause") && (_this.ended() || leave)) {
1414                        target = ctn.find(".h5RepalyTxt");
1415                    } else {
1416                        target = ctn.find('.' + elem.className.split(" ")[0].replace(/Toggle|Btn/g, "") + 'Txt');
1417                    }
1418
1419                    if (target) {
1420                        if (leave) {
1421                            target.fadeOut();
1422                        } else target.fadeIn();
1423                    }
1424
1425                });
1426            });
1427
1428            'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'.split(" ").forEach(function (v) {
1429                document.addEventListener(v, function (evt) {
1430
1431                    ctn.toggleClass('h5FullScreen');
1432
1433                    var exit = ctn.hasClass("h5FullScreen") ? false : true,
1434                        key = exit ? "fullscreen" : "exitFullScreen";
1435
1436                    ctn.find(".h5ContextMenu .h5ToggleFullScreen").html(text[key]);
1437                    ctn.find(".h5floatBoxCtn .h5FullScreenTxt").html(text[key]).hide();
1438                    ctn.find(".h5ToggleFullScreenBtn").html(_this.svg.get.call(_this, key));
1439                    ctn.removeClass("h5MiniPlayerOn");
1440
1441                    //update the position of .h5VolumeTxt
1442                    // _this.setVolume();
1443
1444                    if (exit) {
1445                        _this.miniPlayer.check.call(_this);
1446                    }
1447
1448                    videoAd.resize.call(_this);
1449
1450                });
1451
1452            });
1453
1454        },
1455
1456        addIOSListener: function () {
1457
1458            //for ios player that cannot playsinline
1459            this.video.controls = true;
1460            this.load();
1461
1462            this.container.find(".h5Thumbnail").hide();
1463
1464        },
1465
1466        play: function (input) {
1467
1468            // sometime input is not a function
1469            input = typeof input === "function" ? input : noop;
1470            
1471            var _this = this;
1472
1473            if ( (!this.video.src || this.video.src === window.location.href) && this.src && this.adCompleted && !this.isFlash) {
1474                var play = this.play.bind(this);
1475                this.setVideoSrc(this, function(){
1476                    play(function(){
1477                        this.muted = true;
1478                        play();
1479                    })
1480                    input.call(_this);
1481                });
1482                return
1483            }
1484
1485            var _this = this;
1486            var playPromise = this.video.play();
1487
1488            if (playPromise !== undefined) {
1489                playPromise
1490                    .then(function () { /*sucess*/ })
1491                    .catch(input.bind(_this));
1492            } else if (this.video.paused) {
1493                input.call(_this);
1494            }
1495
1496        },
1497
1498        pause: function () {
1499
1500            if ( !this.adPlaying() ) {
1501                this.video.pause();
1502            }
1503
1504        },
1505
1506        togglePlayPause: function (e) {
1507
1508            var video = this.video;
1509
1510            if (this.adPlaying() || !this.adReady) {
1511                return;
1512            }
1513
1514            if ((video.paused && !video.seeking) || video.ended) {
1515                this.play();
1516            }
1517            else {
1518                this.pause();
1519            }
1520
1521        },
1522
1523        toggleMute: function () {
1524
1525            this.muted = !this.muted;
1526            
1527            if (!this.muted && !this.volume) {
1528                this.volume = 1;
1529            }
1530
1531        },
1532
1533        toggleFullScreen: function () {
1534
1535            var ctn       = this.container,
1536                videoElem = this.video;
1537
1538            if (ctn.hasClass('h5FullScreen')) {
1539
1540                if (document.exitFullscreen) document.exitFullscreen();
1541                else if (document.webkitCancelFullScreen) document.webkitCancelFullScreen();
1542                else if (document.mozCancelFullScreen) document.mozCancelFullScreen();
1543                else if (document.msExitFullscreen) document.msExitFullscreen();
1544                else if (videoElem.webkitExitFullscreen) videoElem.webkitExitFullscreen();
1545
1546            }
1547            else {
1548
1549                //video container request fullscreen is much better then video
1550                if (ctn.requestFullscreen) ctn.requestFullscreen();
1551                else if (ctn.webkitRequestFullScreen) ctn.webkitRequestFullScreen();
1552                else if (ctn.mozRequestFullScreen) ctn.mozRequestFullScreen();
1553                else if (ctn.msRequestFullscreen) ctn.msRequestFullscreen();
1554                else if (this.iOS && videoElem.webkitEnterFullscreen) videoElem.webkitEnterFullscreen();
1555                else {
1556                    ctn.find(".h5ContextMenu .h5ToggleFullScreen").html(text.notSupFullScreen);
1557                    ctn.find(".h5floatBoxCtn .h5FullScreenTxt").html(text.notSupFullScreen2)
1558                        .addClass("h5NotSupport");
1559                }
1560
1561            } 
1562
1563        },
1564
1565        toggleShare: function () {
1566
1567            var ctn = this.container,
1568                txt = !ctn.hasClass("h5ShareOn") ? text.closeShare : text.share;
1569
1570            ctn.toggleClass("h5ShareOn");
1571
1572            ctn.find(".h5ShareTxt").textContent = txt;
1573            ctn.find(".h5ContextMenu .h5ToggleShare").textContent = txt;
1574
1575        },
1576
1577        setVideoSrc: function (data, callback, config) {
1578
1579            data = data || {};
1580            config = config || {};
1581            callback = callback || noop;
1582
1583            var _this          = this,
1584                video          = this.video,
1585                ctn            = this.container,
1586                titleDiv       = this.titleContainer;
1587
1588            var force = config.force; // if true, force update the video src
1589    
1590            if ( isSameVideo(this, data) && !force && (video.src && this.video.src !== window.location.href)) {
1591                return false;
1592            }
1593
1594            if (data.quality === undefined) {
1595                data.quality = {};
1596            }
1597            
1598            if (video.src) {
1599                this.pause();
1600            }
1601            
1602            this.updateProgressBar();
1603
1604            this.usem3u8     = data.usem3u8 || false;
1605            this.updateTime  = data.updateTime || (+new Date());
1606            this.news        = data.news || {};
1607            this.videoId     = data.videoId || "";
1608            this.createTime  = data.createTime || "";
1609            this.posterName  = data.posterName || "";
1610            this.title       = data.title || "";
1611            this.group       = data.group || "";
1612            this.groups      = data.groups || [];
1613            this.keyword     = data.keyword || "";
1614            this.keywords    = data.keywords || [];
1615            this.description = data.description || "";
1616
1617            this.qualities   = data.qualities || [];
1618            this.quality     = (data.quality.level !== undefined && force) ? data.quality.level : 1;
1619
1620            this.lang = data.lang || {};
1621
1622            this.videoDate   = this.fn.dateFormat(new Date(this.createTime * 1000), 'yyyymm');
1623            this.poster      = data.poster || this.poster || "";
1624
1625            var videoQuality = this.quality.type && !this.usem3u8 ? "_" + this.quality.type : "";
1626            var videoFileType = this.usem3u8 ? ".m3u8" : ".mp4";
1627
1628            this.src = config.useSrcInData ?
1629				data.src :
1630				this.config.src && !video.src 
1631					? this.config.src 
1632					: 'http://video.cdn.on.cc/Video/' + this.videoDate + '/' + this.videoId + videoQuality + videoFileType + '?t=' + this.updateTime;
1633            
1634            this.otherVideoList   = [];
1635            this.otherVideoIdList = [this.videoId];
1636            this.otherVideoLoaded = false;
1637
1638            removeAll(ctn.find(".h5OtherVideo"));
1639
1640            video.off("loadedmetadata");
1641
1642            this.relatedNews();
1643            this.nicam.check.call(this);
1644            this.m3u8.destroy.call(this);
1645            this.load(function () {
1646
1647                ctn.removeClass('h5Ended h5Loading');
1648
1649                if (titleDiv) {
1650                    titleDiv.textContent = _this.title;
1651                }
1652
1653                callback.call(_this);
1654                
1655                var tempId = _this.videoId;
1656                video.once("playing", function(){
1657                    if ( tempId == _this.videoId ) {
1658                        _this.track();
1659                    }
1660                });
1661
1662                _this.setting.changeOption.call(_this);
1663
1664                _this.videoReady.call(_this);
1665
1666            });
1667
1668            this.thumbnail = this.poster;
1669
1670        },
1671
1672        popUp: function (config) {
1673
1674            config = config || {};
1675
1676            var _this    = this,
1677                video    = this.video,
1678                ctn      = this.container,
1679                parent   = this.parentPlayer,
1680                popUpCtn = createElement("div", "h5PopUpCtn h5Table" + (this.IE9 ? " h5RubbishIE9" : "")),
1681                cell     = createElement("div", "h5Cell"),
1682                onclose;
1683
1684            if ( document.querySelector(".h5PopUpCtn") ){
1685                document.querySelector(".h5PopUpCtn").style.display = "table";
1686                return;
1687            }
1688
1689            this.disableMiniPlayer = true;
1690
1691            ctn.removeClass("h5MiniPlayerOn");
1692
1693            document.body.appendChild(popUpCtn);
1694
1695            popUpCtn.append(cell);
1696
1697            if ( ctn.parentElement ){
1698
1699                var pCtn = ctn.parentElement,
1700                    index = Array.prototype.indexOf.call(pCtn.children, ctn);
1701                
1702                onclose = function(){
1703                    if ( pCtn.children.length ){
1704                        pCtn.children[index].before(ctn);
1705                    }else{
1706                        pCtn.append(ctn);
1707                    }
1708                    
1709                }
1710
1711            }
1712
1713            cell.append(ctn);
1714            
1715            // mainly for debug
1716            h5Player.prototype.popUpElem = this;
1717
1718            // adjust maximum width of player
1719            var ratioElem            = this.video.parentElement,
1720                maxWindowInnerHeight = screen.height - (window.outerHeight - window.innerHeight),
1721                maxHeight            = maxWindowInnerHeight - 100,
1722                ratio;
1723
1724            ratioElem.className.split(" ").forEach(function (name) {
1725
1726                var splitName = name.split("-");
1727                if (splitName.length === 3 && name.indexOf("h5Ratio") !== -1) {
1728                    ratio = splitName[1] / splitName[2];
1729                }
1730
1731            });
1732
1733            var targetWidth = maxHeight*ratio;
1734            
1735            if ( targetWidth >= 1280 ) {
1736                ctn.css("max-width", "");
1737            } else {
1738                ctn.css("max-width", targetWidth + "px");
1739            }
1740
1741            // popup config
1742            if (this.video.src) {
1743
1744                if (config.restart) {
1745
1746                    if (video.currentTime) {
1747                        video.currentTime = 0;
1748                    }
1749
1750                }
1751
1752                if (config.autoplay !== false) {
1753                    this.autoplay = true;
1754                    this.play();
1755                }
1756
1757                if (config.enableVideoAd) {
1758                    this.videoAd.init.call(this);
1759                }
1760
1761            }
1762            else {
1763
1764                this.autoplay = config.autoplay === undefined ? true : false;
1765                this.enableVideoAd = config.enableVideoAd ? {
1766                    preroll: true,
1767                    postroll: false,
1768                } : false;
1769
1770                if ( ctn.find(".h5ControlsBar") ) {
1771                    this.load();
1772                } else {
1773                    this.load(this.init.bind(this));
1774                }
1775
1776            }
1777
1778            if (parent) {
1779                parent.videoAd.stopAd.call(parent);
1780                parent.pause();
1781            }
1782
1783            popUpCtn
1784                .prepend("<div class='h5Transparent h5AbsLayer'><div class='h5Close'>&#x2715;</div></div>")
1785                .querySelector(".h5PopUpCtn > .h5AbsLayer").onclick = function () {
1786
1787                    _this.videoAd.stopAd.call(_this);
1788
1789                    if (typeof onclose === "function") {
1790                        onclose();
1791                    } else {
1792                        _this.pause();
1793                    }                    
1794
1795                    if (config.remove !== false) {
1796                        popUpCtn.remove();
1797                    } else {
1798                        popUpCtn.hide();
1799                    }
1800
1801                    _this.popUpCloseCallBack();
1802
1803                    h5Player.prototype.popUpElem = undefined;
1804
1805                };
1806
1807        },
1808
1809        switch: function (config, callback) {
1810
1811            config   = config || {};
1812            callback = callback || noop;
1813
1814            var _this  = this,
1815                parent = this.parentPlayer;
1816
1817            function _callback() {
1818
1819                // for videoAd
1820                // parent.autoplay = config.autoplay !== false ? true : false;
1821
1822                if (parent.enableVideoAd.preroll && config.enableVideoAd !== false) {
1823                    parent.videoAd.init.call(parent);
1824                } else if (parent.autoplay || config.autoplay !== false) {
1825                    parent.play();
1826                } else {
1827                    parent.container.removeClass("h5Loading");
1828                    parent.svg.playIcon.set.call(parent, "play");
1829                }
1830
1831                callback.call(parent);
1832
1833            }
1834
1835            if (parent) {
1836
1837                var _config = {
1838                    force: config.force || false
1839                }
1840
1841                if (parent.setVideoSrc(_this, _callback, _config) !== false) {
1842
1843                    parent.container.addClass("h5Loading");
1844                    parent.videoAd.stopAd.call(parent);
1845
1846                    if (config.enableVideoAd !== undefined) {
1847                        parent.enableVideoAd.preroll = config.enableVideoAd ? true : false;
1848                    }
1849
1850                    updateVideoListIndex(parent, _this);
1851
1852                }
1853
1854            } else {
1855
1856                console.log("parentPlayer is not set in config");
1857
1858            }
1859
1860
1861        },
1862
1863        load: function (callback) {
1864
1865            callback = callback || noop;
1866
1867            var _this = this;
1868            var src = this.src || "",
1869                video = this.video,
1870                type =  src.replace(/^.*\.|\?.*/g, '');
1871            
1872            if (src){
1873
1874                if (type === "m3u8") {
1875
1876                    this.m3u8Video = true;
1877                    this.m3u8.init.call(this, callback);
1878
1879                } else if ( video.canPlayType('video/' + type) ) {
1880                    
1881                    this.m3u8Video = false;
1882
1883                    if (video.src != src) {
1884                        video.src = src;
1885                    }
1886
1887                    video.once("loadedmetadata", callback);
1888                    video.load();
1889
1890                } else {
1891                    
1892                    this.pause();
1893                    this.container.removeClass("h5Loading");
1894                    this.thumbnail = "http://hk.on.cc/module/player/img/not_support_video_type.jpg";
1895
1896                }
1897
1898            }
1899            
1900        },
1901
1902        adPlaying: function () {
1903            return this.container.hasClass("h5PlayingAd");
1904        },
1905
1906        playing: function () {
1907            return !this.paused();
1908        },
1909
1910        paused: function () {
1911            return this.video.paused && !this.adPlaying();
1912        },
1913
1914        ended: function () {
1915            return this.video.ended || this.container.hasClass("h5Ended");
1916        },
1917
1918        updateProgressBar: function (input) {
1919
1920            input = input || {
1921                curr: 0,
1922                total: 1,
1923                removeTransistion: true,
1924            };
1925
1926            var ctn = this.container,
1927                bar = ctn.find(".h5ProgressBar"),
1928                dot = ctn.find(".h5ProgressBarCtn .h5Dot"),
1929                times = ctn.find(".h5CurrentTime");
1930
1931            input.pct = input.pct || input.curr / input.total;
1932
1933            if (bar) {
1934
1935                if (input.removeTransistion) {
1936                    bar.removeClass("h5Transition");
1937                }
1938
1939                bar.style.width = input.pct * 100 + "%";
1940
1941            }
1942
1943            
1944            dot && dot.css({
1945                left: "calc(" + input.pct * 100 + "% - " + dot.clientWidth / 2 + "px)"
1946            });
1947            
1948            times && times.html(timeFormat(input.curr));
1949            
1950        },
1951
1952        track: function () {
1953
1954            if (!this.videoId) return;
1955
1956            var _this = this;
1957
1958            var videoFileType = this.usem3u8 ? ".m3u8" : ".mp4";
1959            var videoQuality = this.quality.type ? "_" + this.quality.type : "";
1960            var para1 = _this.trackPath() + this.videoId + videoQuality + videoFileType;
1961            var para2 = 'HKVV';
1962            var para3 = ( this.currLang && this.lang["CN"] && this.currLang.vid === this.lang["CN"].vid ) ? "_cn" : "";
1963
1964            para1 += para3;
1965
1966            if (typeof urchinTracker == 'function') {
1967
1968                var iframePath = 'http://tv.on.cc/utm/video_view_counter.html?para2=' + para2 + '&para1=' + para1 + '&title=' + encodeURIComponent(_this.title) + '&t=' + (+new Date());
1969                this.container.find('.tracking').html('<iframe class="trackingIframe" src="' + iframePath + '"></iframe>');
1970
1971            } 
1972
1973            log("track video view : " + para1);
1974
1975        },
1976
1977        trackPath: function () {
1978
1979            var platform = this.mobile ? "mobileweb": "web";
1980            var domain   = window.location.hostname;
1981
1982            switch (domain) {
1983                case 'orientaldaily.on.cc':
1984                case 'odn.preview.prod.cms':
1985                    domain = 'odn';
1986                    break;
1987                case 'tv.on.cc':
1988                    domain = 'ontv';
1989                    break;
1990                case '202.125.90.157':
1991                    domain = 'hk';
1992                    break;
1993                case '202.125.90.158':
1994                    domain = 'tw';
1995                    break;
1996                case '202.125.90.159':
1997                    domain = 'cn';
1998                    break;
1999                case '127.0.0.1':
2000                    domain = 'localhost';
2001                    break;
2002                default:
2003                    domain = domain.replace('.on.cc', '');
2004            }
2005
2006            var section = '';
2007            var lang = '';
2008
2009            try {
2010
2011                if (domain == 'odn') {
2012
2013                    if (this.mobile) {
2014                        section = '/' + ODN.sect;
2015                    } 
2016                    // else {
2017
2018                    // }
2019                }
2020
2021                if (domain == 'hk' || domain == 'cn' || domain == 'tw') {
2022
2023                    var ONCCPlayerFunction;
2024                    if (this.mobile) {
2025                        ONCCPlayerFunction = ONCC.Function;
2026                        lang = '/' + ((ONCC.Function.getLang() === '') ? 'zh-hk' : 'zh-cn');
2027                    } else {
2028                        ONCCPlayerFunction = ONCC;
2029                        lang = '/' + ((ONCC.curLang === '') ? 'zh-hk' : 'zh-cn');
2030                    }
2031                    if (ONCCPlayerFunction.getSection() == 'news' || ONCCPlayerFunction.getSection() == 'commentary') {
2032                        section = '/' + ONCCPlayerFunction.getLocation() + '_' + ONCCPlayerFunction.getSection();
2033                    } else {
2034                        section = '/' + ONCCPlayerFunction.getSection();
2035                    }
2036
2037                }
2038
2039                if (domain == 'ontv') {
2040                    section = '/' + ONTV.curSection;
2041                }
2042
2043                if (domain == 'money18') {
2044
2045                    if ($('body').hasClass('index')) {
2046                        section = '/index';
2047                    } else {
2048                        section = '';
2049                    }
2050                }
2051
2052                // if (domain == 'racing') {
2053
2054                // }
2055
2056            }
2057            catch (err) {
2058
2059            }
2060
2061            return '/' + platform + '/' + domain + lang + section + '/';
2062        },
2063
2064        relatedNews: function () {
2065
2066            var _this = this,
2067                btn = this.container.find(".h5ToggleNews");
2068
2069            if (!btn) return;
2070
2071            if (this.disableRelatedNews || !( this.news && this.news.length )) {
2072                btn.hide();
2073            } else {
2074
2075                var news,
2076                    loc = /\/tw\//.test(window.location.href) ? "tw" : "hk";
2077
2078                this.news.forEach(function (_news) {
2079                    if (new RegExp(loc + ".on.cc").test(_news.url)) {
2080                        news = _news;
2081                    }
2082                });
2083
2084                if (news) {
2085
2086                    if ((new RegExp(news.articleId).test(window.location.href))) {
2087                        btn.hide();
2088                    } else {
2089                        btn.show();
2090                        btn.onclick = function () {
2091                            newTab(news.url, _this);
2092                        };
2093                    }
2094
2095                }
2096
2097            }
2098
2099        },
2100
2101        customShareUrl: function (type) {
2102            return false;
2103        },
2104
2105        customShareFunction: function (type) {
2106            return true;
2107        },
2108
2109        storage: {
2110            videos: {},
2111            groups: {},
2112            keywords: {},
2113            mostview: {}
2114        },
2115
2116        commonConfig: {}
2117
2118    };
2119    h5Player.prototype.contextMenu = {
2120
2121        init: function() {
2122
2123            var _this = this,
2124                ctn   = this.container,
2125                video = this.video,
2126                menu  = ctn.find(".h5ContextMenu");
2127
2128            menu.html(
2129                '<div class="h5Row h5Copy">' + text.copyURL + '</div>' +
2130                '<div class="h5Row h5LoopBtn">'+
2131                    '<div class="h5Cell">' + text.loop + '</div>'+
2132                    '<div class="h5Cell"><div class="h5Tick"></div></div>'+
2133                '</div>' +
2134                '<div class="h5Row h5ToggleControlsBar">' + text.hideCtrlBar + '</div>' +
2135                '<div class="h5Row h5ToggleMute">' + text.mute + '</div>' +
2136                '<div class="h5Row h5ToggleFullScreen">' + text.fullscreen + '</div>' +
2137                '<div class="h5Row h5ToggleShare">' + text.share + '</div>');
2138
2139            menu.find(".h5Copy").on("click", function() {
2140                _this.contextMenu.copyToClipboard.call( _this , ctn.find("textarea"));
2141            });
2142
2143            menu.find(".h5LoopBtn").on("click", function() {
2144                video.loop = !video.loop;
2145                this.find(".h5Tick").style.display = video.loop ? "block" : "none";
2146            });
2147
2148            menu.find(".h5ToggleControlsBar").on("click", function() {
2149                ctn.toggleClass("h5HideCtrl_IM");
2150                this.textContent = ctn.hasClass("h5HideCtrl_IM") ? text.shwoCtrlBar : text.hideCtrlBar;
2151            });
2152
2153            menu.find(".h5ToggleMute").on("click", _this.toggleMute.bind(_this));
2154
2155            menu.find(".h5ToggleShare").on("click", _this.toggleShare.bind(_this));
2156
2157            menu.find(".h5ToggleFullScreen").on("click", _this.toggleFullScreen.bind(_this));
2158
2159            domElem.on.call( window, "mouseup touched", function hideContextMenu(evt){
2160                if (evt.button || evt.button === 0) {
2161                    if (evt.button !== 2) ctn.removeClass("h5ContextMenuOn");
2162                }
2163            });
2164
2165        },
2166
2167        copyToClipboard: function(textarea) {
2168
2169            var _this = this;
2170
2171            textarea.value = _this.share.link.call(_this, 'link');
2172            textarea.select();
2173
2174            try {
2175                _this.copyStatus = document.execCommand('copy') ? 'success' : 'fail';
2176            }
2177            catch (err) {
2178                _this.copyStatus = 'fail';
2179            }
2180
2181            if (_this.copyStatus === "fail") {
2182                setTimeout(function() {
2183                    window.prompt(text.prompt, textarea.value);
2184                }, 200);
2185            }
2186                
2187
2188        }
2189
2190    };
2191
2192    h5Player.prototype.m3u8 = {
2193        
2194        init : function(callback) {
2195
2196            callback = callback || noop;
2197            
2198            var _this = this;
2199            var m3u8 = this.m3u8;
2200            var isIE = document.documentMode || false;
2201
2202            if (typeof Hls === "undefined") {
2203           
2204                this.fn.loadScript("https://cdn.jsdelivr.net/npm/hls.js@latest", function(){
2205                    _this.hlsCallBacks.forEach(function(fn){
2206                        fn();
2207                    })
2208                });
2209
2210                this.hlsCallBacks.push(_this.m3u8.init.bind(_this, callback));
2211                
2212                return;
2213            }
2214
2215            if (Hls.isSupported()) {
2216                        
2217                var video = this.video;
2218                var hls = new Hls({
2219                    liveSyncDurationCount: 2,
2220                    liveMaxLatencyDurationCount: 3,
2221                });
2222                
2223                hls.loadSource(this.src);
2224                hls.attachMedia(video);
2225                hls.on(Hls.Events.LEVEL_LOADED, function initLevel(){
2226                    hls.off(Hls.Events.LEVEL_LOADED, initLevel);
2227
2228                    _this.hls = hls;
2229                    
2230                    m3u8.updateQuality.call(_this, hls.levels);
2231                    
2232                    _this.setting.changeOption.call(_this);
2233                                    
2234                });
2235
2236                hls.on(Hls.Events.MANIFEST_PARSED, function parsed(){
2237                    hls.off(Hls.Events.MANIFEST_PARSED, parsed);
2238                    callback.call(_this);
2239                });
2240
2241                hls.on(Hls.Events.ERROR, function (event, data) {
2242
2243                    if ( data.details === "manifestLoadTimeOut") {
2244                        ctn.removeClass("h5Loading");
2245                    }
2246
2247                    if (data.fatal) {
2248                        switch(data.type) {
2249                            case Hls.ErrorTypes.NETWORK_ERROR:
2250                                // try to recover network error
2251                                console.log("fatal network error encountered, try to recover");
2252                                hls.startLoad();
2253                                break;
2254                            case Hls.ErrorTypes.MEDIA_ERROR:
2255                                console.log("fatal media error encountered, try to recover");
2256                                hls.recoverMediaError();
2257                                break;
2258                            default:
2259                                console.log("fatal media error encountered, cannot recover");
2260                                hls.destroy();
2261                                break;
2262                        }
2263                    }
2264                });
2265                
2266            } else if ( this.video.canPlayType("application/x-mpegurl") !== "" ) {
2267                m3u8.native.call(this, callback);
2268            } else if ( !this.mobile && this.live ) {
2269                m3u8.flash.call(this);
2270            } else {
2271                m3u8.fallback.call(this);
2272            }
2273            
2274        },
2275
2276        native: function(callback) {
2277
2278            var _this = this;
2279            var m3u8 = this.m3u8;
2280
2281            this.fn.ajax({
2282                url : this.src,
2283                dataType: "text",
2284                success : function(data){
2285
2286                    var levels = m3u8.filterLevels.call(_this, data);
2287                    
2288                    m3u8.updateQuality.call(_this, levels);
2289
2290                    levels.splice(0, 0, {
2291                        url : _this.src,        
2292                    });
2293
2294                    _this.hls = {
2295                        native : true,
2296                        levels : levels,
2297                    };
2298
2299                    _this.video.once("loadedmetadata", callback.bind(_this));
2300                    _this.video.src = _this.src;
2301                    _this.video.load();
2302                    
2303                    _this.setting.changeOption.call(_this);
2304
2305                }
2306            });
2307
2308        },
2309
2310        updateQuality: function(levels) {
2311
2312            var _this = this;
2313            
2314            this.quality = 0;
2315            this.qualities = [];
2316            
2317            if ( levels.length > 1 ) {
2318
2319                levels.forEach(function(v,k){
2320                    _this.qualities.push({
2321                        level: k+1,
2322                        type: "",
2323                        pixel: v.height + "p"
2324                    });
2325                });
2326
2327                _this.qualities.splice(0,0, {
2328                    level: 0,
2329                    type: "",
2330                    pixel: "自動"
2331                })
2332            }
2333
2334        },
2335
2336        flash: function() {
2337
2338            this.video.src = null;
2339
2340            if (typeof swfobject === "undefined") {
2341                this.fn.loadScript("http://hk.on.cc/module/player/swfobject.js", this.m3u8.flash.bind(this));
2342                return;
2343            }
2344            
2345            swfobject.removeSWF('onccFlashPlayer');
2346
2347            var container = this.container.find(".h5MiniPlayer") || this.container;
2348            var swf =  'http://hk.on.cc/module/player/liveplayer.swf';
2349            var swfUrl = swf + '?nation=hk&t=' + (+new Date()) + '&liveStreamPath=' + this.src  + '?.mp4';
2350            var options = {
2351                hls_debug: false,
2352                hls_debug2: false,
2353                hls_minbufferlength: -1,
2354                hls_lowbufferlength: 2,
2355                hls_maxbufferlength: 60,
2356                hls_startfromlowestlevel: false,
2357                hls_seekfromlowestlevel: false,
2358                hls_live_flushurlcache: false,
2359                hls_seekmode: 'ACCURATE',
2360                hls_capleveltostage: false,
2361                hls_maxlevelcappingmode: 'downscale'
2362            }
2363            
2364            var params = {
2365                allowFullScreen: true,
2366                allowScriptAccess: 'always',
2367                wmode: 'opaque',
2368                hasPriority: true
2369            }
2370
2371            container.append('<div id="onccFlashPlayer"></div>')
2372
2373            swfobject.embedSWF(swfUrl,"onccFlashPlayer","100%","100%","10.0.0","expressInstall.swf", options, params, {
2374                name: 'onccFlashPlayer'
2375            });
2376
2377
2378        },
2379        
2380        filterLevels : function(data) {
2381            
2382            var _this = this;
2383            var levels = [];
2384
2385            data = data.trim().split("#");
2386            data = data.slice(3, data.length);
2387            data.forEach(function(v){
2388
2389                if (/EXT-X-STREAM-INF/.test(v)) {
2390                    
2391                    v = v.split("\n");
2392
2393                    var filename = v[1];
2394
2395                    function getParam(name, str) {
2396                        str = str || v[0];
2397                        var regex = new RegExp("[\:|,]" + name + "(=([^&#]*)|&|#|$)"),
2398                            results = regex.exec(str);
2399                        if (!results) return null;
2400                        if (!results[2]) return '';
2401                        return decodeURIComponent(results[2].replace(/,.*/g, ""));
2402                    }
2403
2404                    var resolution = getParam("RESOLUTION");
2405                    var width = resolution.split("x")[0];
2406                    var height = resolution.split("x")[1];
2407
2408                    levels.push({
2409                        url : _this.src.replace(/([^/]*)$/,"") + filename,
2410                        filename : filename,
2411                        bandwidth : getParam("BANDWIDTH"),
2412                        codecs : getParam("CODECS"),
2413                        resolution : resolution,
2414                        width : width,
2415                        height : height
2416                    });
2417                    
2418                }
2419
2420            });
2421
2422            return levels.sort(function(a,b){
2423                return (Number(a.height) - Number(b.height));
2424            });
2425
2426        },
2427
2428        destroy: function(){
2429            if ( this.hls ) {
2430
2431                if ( this.hls.destroy ) {
2432                    this.hls.detachMedia();
2433                    this.hls.destroy();
2434                } else {
2435                    this.video.src = "";
2436                }
2437
2438                this.hls = {};
2439
2440            }
2441        },
2442
2443        startLoad: function(startPosition) {
2444
2445            startPosition = startPosition || -1;
2446
2447            if ( this.hls ) {
2448                if ( this.hls.startLoad ) {
2449                    this.hls.startLoad();
2450                }
2451            }
2452            
2453        },
2454
2455        stopLoad: function() {
2456
2457            if ( this.hls ) {
2458                if ( this.hls.stopLoad ) {
2459                    this.hls.stopLoad();
2460                }
2461            }
2462
2463        },
2464
2465        fallback: function() {
2466
2467            var _this = this;
2468            var ctn = this.container;
2469
2470            if ( !_this.poster && this.live ) {
2471                this.thumbnail = "http://hk.on.cc/module/player/img/live_thumbnail.png";
2472            }
2473
2474            this.container
2475                .css("cursor", "pointer")
2476                .removeClass("h5Loading")
2477                .on("click",function(){
2478                    console.log("HI")
2479                    window.open(_this.src, "_blank");
2480                });
2481                
2482        }
2483        
2484        
2485    };
2486    
2487    h5Player.prototype.miniPlayer = {
2488
2489        init: function() {
2490
2491            if (this.disableMiniPlayer || this.mobile) return;
2492
2493            var _this      = this,
2494                ctn        = this.container,
2495                miniPlayer = this.miniPlayer,
2496                div        = createElement("div","h5MiniPlayer"),
2497                dragDiv    = createElement("div","h5Draggable"),
2498                check      = miniPlayer.check.bind(_this);
2499
2500            // wrapAll
2501            while (ctn.firstChild) {
2502                div.appendChild(ctn.firstChild);
2503            }
2504
2505            dragDiv
2506                .append(div)
2507                .prepend('<div class="h5CloseMiniPlayer">&#x2715;</div>' +
2508                         '<div class="h5pDragCtrl"></div>');
2509
2510            ctn.appendChild(dragDiv);
2511
2512            miniPlayer.check.call(_this);
2513            miniPlayer.drag(dragDiv.find(".h5pDragCtrl"));
2514            miniPlayer.disable = function(){
2515                window.removeEventListener("scroll", check);
2516                ctn.removeClass("h5MiniPlayerOn").css("height","");
2517                _this.disableMiniPlayer = true;
2518                _this.videoAd.resize.call(_this);
2519            };
2520
2521            dragDiv.find(".h5CloseMiniPlayer").onclick = miniPlayer.disable;
2522
2523            window.addEventListener("scroll", check);
2524
2525        },
2526
2527        check: function() {
2528
2529            if ( this.mobile || 
2530                 this.disableMiniPlayer ||
2531                !document.querySelector(".h5MiniPlayer") || 
2532                document.querySelector(".h5PopUpCtn .h5PlayerCtn") === this.container ){
2533                return;
2534            }
2535
2536            var ctn     = this.container,
2537                video   = this.video,
2538                scrollY = window.pageYOffset;
2539
2540            if ((scrollY >= ctn.offsetTop + ctn.offsetHeight) && scrollY > 0 && document.body.clientWidth > 768 ) {
2541
2542                if( !ctn.hasClass("h5MiniPlayerOn") ){
2543
2544                    // height should set before addClass "h5MiniPlayerOn"
2545                    ctn.css("height",video.clientHeight + "px").addClass("h5MiniPlayerOn");
2546                    this.videoAd.resize.call(this);
2547                }
2548
2549
2550            }
2551            else if (ctn.hasClass("h5MiniPlayerOn")){
2552                ctn.removeClass("h5MiniPlayerOn").css("height","");
2553                this.videoAd.resize.call(this);
2554            }
2555
2556        },
2557
2558        drag: function(el) {
2559
2560            var x, y;
2561            var move = function(e) {
2562
2563                e.preventDefault();
2564
2565                el.parent().css({
2566                    left: e.clientX - x + "px",
2567                    top: e.clientY - y + "px",
2568                });
2569
2570
2571            };
2572
2573            el.addEventListener("mousedown", function(e) {
2574
2575                e.preventDefault();
2576
2577                x = e.offsetX;
2578                y = e.offsetY;
2579
2580                window.addEventListener("mousemove", move);
2581
2582                domElem.once.call(window,"mouseup",function(){
2583                    window.removeEventListener("mousemove", move);
2584                });
2585
2586            });
2587
2588        },
2589
2590        disable : function(){
2591            // defined in MiniPlayer.init
2592        }
2593
2594
2595    };
2596
2597h5Player.prototype.nicam = {
2598
2599	init: function () {
2600		
2601		var _this = this;
2602		var parent = this.container.find(".h5Nicam");
2603
2604		parent && parent.on("click",function(){
2605			if ( /url\(.*.\)/.test( this.css("background-image") ) ) {
2606				this.toggleClass("show");
2607			}
2608		}).find(".h5Cell > div").forEach(function($btn) {
2609
2610			var rel = $btn.getAttribute("rel");
2611
2612			$btn.on("click", function() {
2613				if ( !this.hasClass("on") ) {
2614					_this.nicam.change.call(_this, rel);
2615				}
2616			});
2617
2618			if ( rel === (_this.fn.getCookie("h5Nicam") || "HK") ) {
2619				$btn.addClass("on");
2620			}
2621
2622		});
2623
2624		this.nicam.check.call(this);
2625
2626	},
2627
2628	check: function() {
2629		var $elem = this.container.find(".h5Nicam");
2630		$elem && $elem.css("display", Object.keys(this.lang || {}).length > 1 ? "table" : "none");
2631	},
2632
2633	change: function (type) {
2634
2635		var _this = this;
2636		var ctn = this.container;
2637		var video = this.video;
2638		var ended = this.ended();
2639		var curr = video.currentTime / video.duration;
2640		var playing = !video.paused;
2641		var $target = ctn.find('.h5Nicam div[rel="'+ type +'"]');
2642		var $on = ctn.find(".h5Nicam .on");
2643
2644		this.currLang = type;
2645		
2646		new h5Player({
2647			videoId: this.currLang.videoId,
2648			createTime: this.currLang.createTime,
2649			lang: this.lang,
2650			preload: false,
2651			parentPlayer: this,
2652			xmlLoaded: function() {
2653									
2654				// this.quality = _this.quality.level;
2655
2656				this.switch({
2657					force: true,
2658					autoplay: false,
2659					enableVideoAd: false
2660				}, function(){
2661
2662					if (playing || ended) {
2663						_this.play();
2664					}
2665
2666					if( curr > 0 ){
2667						_this.video.currentTime = ended ? 0 : curr * this.video.duration;
2668					}
2669				});
2670
2671			}
2672		});
2673
2674		$on.removeClass("on");
2675		$target.addClass("on");
2676			
2677
2678	}
2679
2680}    
2681    h5Player.prototype.otherVideo = {
2682
2683        init: function() {
2684
2685            var ctn   = this.container,
2686                order = this.otherVideoOrder.slice(0);
2687
2688            ctn.addClass("h5Loading");
2689
2690            this.year = {
2691                curr : new Date().getFullYear(),
2692                temp : new Date().getFullYear(),
2693            };
2694
2695            // this.otherVideoList = this.otherVideoList || [];
2696            // console.log(this.container)
2697
2698            if (this.disableOtherVideo || this.otherVideoList.length) {
2699                this.otherVideo.ready.call(this);
2700            } else {
2701                ctn.find(".h5LoadingLayer").before('<div class="h5OtherVideo h5AbsLayer"><div class="h5Table h5Transparent h5AbsLayer"><div class="h5Cell"></div></div></div>');
2702                this.otherVideo.check.call(this,order);
2703            }
2704
2705            this.video.once("playing",function(){
2706                try{
2707                    ctn.find(".h5OtherVideo").hide();
2708                }catch(e){}
2709            });
2710
2711        },
2712
2713        check: function(order) {
2714
2715            var _this      = this,
2716                otherVideo = this.otherVideo;
2717
2718            function load( type, value, info ){
2719
2720                var _year = _this.year.temp;
2721
2722                h5Player.fn.loadXML('http://datafeed.on.cc/ontv/xml/'+ type +'/' + _year + '/' + value + '_' + _year + '.xml', function(xml){
2723
2724                    var list = xml.querySelectorAll("video");
2725                    otherVideo.loop.call( _this , list.length, function(i) {
2726
2727                        var id   = list[i].textContent,
2728                            time = list[i].getAttribute("createTime");
2729
2730                        if (_this.createTime !== time && _this.videoId != id) {
2731                            return [time, id];
2732                        }
2733
2734                    }, {
2735                        type : type,
2736                        val : info,
2737                    });
2738
2739                },noop, false)
2740
2741            }
2742
2743            var related   = /related/i.test(order[0]),
2744                group     = /group/i.test(order[0]),
2745                mostview  = /mostview/i.test(order[0]),
2746                videolist = /videolist/i.test(order[0]),
2747                custom    = typeof order[0] === "object";
2748            
2749            if (order.length && _this.otherVideoList.length < 6) {
2750
2751                if ( related && this.keywords.length ) {
2752                    for( var k=0; ( k < this.keywords.length && _this.otherVideoList.length<6 ); k++ ){
2753                        load("Keyword", _this.keywords[k][1], _this.keywords[k][0]);
2754                    }
2755                }
2756                else if ( group && _this.group ) {
2757                    load("Group", _this.group, _this.group);
2758                }
2759                else if( mostview && _this.group ){
2760
2761                    h5Player.fn.loadXML( "http://datafeed.on.cc/ontv/xml/Ranking/most_view_"+ _this.group +".xml", function(xml){
2762
2763                        var list = xml.querySelectorAll("video");
2764                        otherVideo.loop.call( _this, list.length, function(i){
2765
2766                            var id   = list[i].querySelector("meta").textContent.trim(),
2767                                time = list[i].querySelector("createTime").textContent.trim();
2768
2769                            if (_this.createTime !== time && _this.videoId != id) {
2770                                return [time, id];
2771                            }
2772
2773                        }, {
2774                            type : "mostview",
2775                            val : _this.group,
2776                        });
2777
2778                    }, noop, false)
2779
2780                }
2781                else if ( videolist && !_this.disablePlayNext) {
2782
2783                    var _videoList = _this.videoList.slice(0);
2784                    if (_this.videoListRepeat && _this.videoListIndex + 6 > _this.videoList.length-1) {
2785                        // console.log("fill")
2786                        for (var i = _this.videoListIndex; i < (_this.videoListIndex + 6); i++) {
2787                            if( _this.videoList[i] ){
2788                                _videoList.push(_this.videoList[i]);
2789                            }
2790                            
2791                        }
2792                    }
2793
2794                    otherVideo.loop.call( _this , _videoList.length, function(i) {
2795                        return _videoList[_this.videoListIndex + 1 + i];
2796                    }, {
2797                        type : "videoList",
2798                        val : ""
2799                    });
2800
2801                }
2802                else if ( custom ) {
2803
2804                    otherVideo.loop.call( _this , order[0].length, function(i) {
2805                        return order[0][i];
2806                    }, {
2807                        type : "custom",
2808                        val : ""
2809                    });
2810
2811                }
2812
2813                if( ( !related && !group && !mostview ) || _this.year.curr - _this.year.temp >= 2 ){
2814                    order.splice(0, 1);
2815                    _this.year.temp = _this.year.curr;
2816                }
2817                else{
2818                    _this.year.temp--;
2819                }
2820                otherVideo.check.call(_this,order);
2821                
2822                
2823            }else{
2824
2825                if (!_this.otherVideoList.length) {
2826                    log("no other video");
2827                    removeAll( _this.container.find(".h5OtherVideo") );
2828                }
2829
2830                otherVideo.ready.call(_this);
2831
2832            }
2833
2834        },
2835
2836        loop: function(max, _arr, info) {
2837
2838            var _this      = this,
2839                otherVideo = this.otherVideo;
2840            
2841            for (var i = 0; i < max; i++) {
2842
2843                if (_this.otherVideoList.length >= 6) break;
2844                
2845                var obj = _arr(i); // arr(i)  return [ createTime , videoId ]
2846
2847                if (obj) {
2848
2849                    var id = obj.videoId || obj[1];
2850
2851                    if( _this.otherVideoIdList.indexOf( id ) === -1 ){
2852
2853                        // related video may equal to following video in videoList, idList prevent duplicate
2854                        _this.otherVideoList.push(obj);
2855                        _this.otherVideoIdList.push(id);
2856
2857                        (function(index){
2858
2859                            var elem = createElement("div","h5OtherVideoBox");
2860
2861                            _this.container.find(".h5OtherVideo .h5Cell").appendChild(elem);
2862
2863                            _this.fn.loadXML( obj, function(xml){
2864
2865                                xml = filterXMLData(xml);
2866                                
2867                                // var groupString = Array.prototype.concat.apply([], xml.groups.slice(0)).join();
2868
2869                                // if ( /停用/.test(groupString) ) {
2870                                //     log('[otherVideo] rejected as it contains disabled group', xml.groups);
2871                                //     elem.remove();
2872                                // } else {
2873                                    otherVideo.createOtherVideoBox.call(_this, xml, elem, info);
2874                                // }
2875
2876                            });
2877
2878                        }(i));
2879
2880                    }
2881
2882                }
2883            }
2884
2885        },
2886
2887        createOtherVideoBox: function(xml, elem, info) {
2888
2889            var _this     = this,
2890                time      = new Date(xml.createTime * 1000),
2891                yyyymm    = _this.fn.dateFormat(time, 'yyyymm'),
2892                thumbSzie = screen.width <= 480 ? "" : "bigthumbnail",
2893                thisYear  = yyyymm.substring(0, 4) === String(_this.year.curr),
2894                format    = thisYear ? text.dateFormat : text.dateFormat2,
2895                thumbnail = 'http://tv.on.cc/xml/Thumbnail/' + yyyymm + '/' + thumbSzie + '/' + xml.posterName,
2896                clickAction;            
2897                    
2898            elem.append(
2899                '<div class="h5RatioParent h5Ratio-16-9">'+
2900                    '<div class="h5RatioChild h5BgThumbnail" style="background-image:url('+ thumbnail +')"></div>'+
2901                    // '<img class="h5RatioChild" src="'+ thumbnail +'">'+
2902                '</div>' +
2903                '<div class="h5AbsLayer h5Info">' +
2904                    '<div class="h5Date">' + _this.fn.dateFormat(time, format) + '</div>' +
2905                    '<div class="h5Title">' + xml.title + '</div>' +
2906                '</div>' +
2907                '<div class="h5AbsLayer h5HelperElem" style="display: flex;opacity:1">' +
2908                    '<div class="h5OtherVideoTtype">'+
2909                        '<div>'+ info.type +'</div>' +
2910                        '<div>'+ info.val +'</div>' +
2911                    '</div>' +
2912                '</div>'
2913            );
2914
2915            // elem.find(".h5RatioParent img").onload = function(){
2916            //     this.elem.style.backgroundImage = "url("+ this.src +")";
2917            //     this.remove();
2918            // }
2919
2920            if (_this.otherVideoClickAction == "switch") {
2921
2922                clickAction = function() {
2923
2924                    if (!_this.disablePlayNext) {
2925
2926                        updateVideoListIndex(_this, xml);
2927
2928                    }
2929
2930                    _this.setVideoSrc( xml, _this.play.bind(_this) );
2931
2932                };
2933
2934            }
2935            else {
2936
2937                clickAction = _this.otherVideoClickAction || function( xml ) {
2938                    window.open( 'http://tv.on.cc/hk/index.html?i=' + xml.videoId + '&d=' + xml.createTime + '&s=' + ( xml.group || 3 ) );
2939                };
2940
2941            }
2942
2943            // elem.addClass("h5Expend");
2944            elem.onclick = clickAction.bind( _this, xml );
2945
2946        },
2947
2948        ready : function(){
2949
2950            this.container.find(".h5Thumbnail").show();
2951            this.container.removeClass("h5Loading");
2952
2953            var el = this.container.find(".h5OtherVideo");
2954
2955            if (el) {
2956                el.show();
2957                // this.video.once("playing",el.hide.bind(el));
2958            }
2959
2960            
2961
2962        }
2963
2964    };
2965
2966    h5Player.prototype.playNext = {
2967
2968        init: function() {
2969
2970            if (this.disablePlayNext || !this.loadNext) {
2971
2972                this.otherVideo.init.call(this);
2973
2974                return;
2975
2976            }
2977
2978            if ( this.videoListIndex === this.videoList.length - 1 && this.videoListRepeat && this.videoList.length >= 2 ) {
2979                this.videoListIndex = -1;
2980            }
2981
2982            var next = this.videoList[this.videoListIndex + 1];
2983
2984            if (next) {
2985
2986                var id   = next[1] || next.videoId,
2987                    time = next[0] || next.createTime;
2988
2989                if (time == this.createTime && id == this.videoId) {
2990
2991                    this.videoListIndex++;
2992                    this.playNext.init.call(this);
2993
2994                } else {
2995                    
2996                    var action = this.playNext.load.bind(this);
2997
2998                    if ( next instanceof h5Player ) {
2999                        this.next = next;
3000                        action();
3001                    } else {
3002                        this.next = new h5Player({
3003                            videoId: id,
3004                            createTime: time,
3005                            preload: false,
3006                            xmlLoaded: action
3007                        })
3008                    }
3009
3010                }
3011
3012            } else {
3013
3014                this.otherVideo.init.call(this);
3015
3016            }
3017
3018        },
3019
3020        load: function() {
3021
3022            var _this    = this,
3023                playNext = this.playNext,
3024                ctn      = this.container;
3025
3026            if (_this.timeOutForPlayNext) {
3027
3028                removeAll( ctn.find(".h5PlayNext") );
3029
3030                ctn.find(".h5LoadingLayer").before('<div class="h5PlayNext h5AbsLayer"><div class="h5Table"><div class="h5Cell"></div></div></div>');
3031
3032                var layer = ctn.find(".h5PlayNext");
3033
3034                layer.find(".h5Cell").html(
3035                    '<div class="h5NextUp">' + text.nextUp + '</div>' +
3036                    '<div class="h5Close">&#x2715;</div>' +
3037                    '<div class="h5Title">'+ _this.next.title +'</div>' +
3038                    '<div class="h5Spinner">' +
3039                        _this.svg.playIcon.html.call(_this) +
3040                        '<svg class="h5Circle" width="60" height="60" viewbox="0 0 60 60"><circle cx="30" cy="30" r="30"/><path class="h5border" fill="#FFF" transform="translate(30, 30)"/><circle id="donut" cx="30" cy="30" r="27"/></svg>
3040' +
3041                    '</div>' + // close h5pSpinner
3042                    '<div class="h5Cancel">' + text.cancel + '</div>');
3043
3044
3045                layer.find(".h5Spinner").on("click", playNext.play.bind(_this));
3046                layer.find(".h5Close").on("click", playNext.cancel.bind(_this));
3047                layer.find(".h5Cancel").on("click", playNext.cancel.bind(_this));
3048
3049                playNext.timer.call(_this);
3050
3051                _this.video.once("playing",playNext.cancel.bind(_this));
3052
3053            } else {
3054
3055                playNext.play.call(_this);
3056
3057            }
3058
3059        },
3060
3061        play: function() {
3062            
3063            var _this = this;
3064
3065            this.playNext.cancel.call(this);
3066
3067            this.videoListIndex++;
3068
3069            if ( this.videoListIndex == this.videoList.length && this.videoListRepeat ) {
3070                this.videoListIndex = 0;
3071            }
3072
3073            this.container.addClass("h5Loading");
3074
3075            if ( !isSameVideo(this, this.next) ) {
3076                
3077                this.videoAd.stopAd.call(this);
3078                this.setVideoSrc(this.next, function(){
3079
3080                    _this.autoplay = true;
3081
3082                    if (_this.enableVideoAd.preroll) {
3083                        _this.videoAd.init.call(_this);
3084                    } else {
3085                        _this.play.call(_this);
3086                    }
3087
3088                    _this.playNextCallBack.call(_this);
3089
3090                });
3091
3092            }           
3093
3094        },
3095
3096        cancel: function(evt) {
3097
3098            clearTimeout(this.playNextTimeout);
3099
3100            removeAll( this.container.find(".h5PlayNext") );
3101
3102            if (evt) {
3103                if (domElem.hasClass.call(evt.currentTarget, "h5Cancel h5Close")) {
3104                    this.otherVideo.init.call(this);
3105                }
3106            }
3107
3108        },
3109
3110        timer: function() {
3111
3112            var _this  = this,
3113                a      = 0,
3114                p      = Math.PI,
3115                t      = _this.timeOutForPlayNext;
3116
3117            t = t / 360 * 1000;
3118
3119            (function draw() {
3120
3121                a++;
3122                a %= 360;
3123                var r = (a * p / 180),
3124                    x = Math.sin(r) * 125,
3125                    y = Math.cos(r) * -125,
3126                    mid = (a > 180) ? 1 : 0,
3127                    anim = 'M 0 0 v -125 A 125 125 1 ' +
3128                    mid + ' 1 ' +
3129                    x + ' ' +
3130                    y + ' z';
3131
3132                _this.container.find('.h5PlayNext .h5border').setAttribute('d', anim);
3133
3134                if (a === 0) {
3135                    _this.playNext.play.call(_this);
3136                }
3137                else {
3138                    _this.playNextTimeout = setTimeout(draw, t);
3139                }
3140
3141            })();
3142
3143        }
3144
3145    };
3146
3147    h5Player.prototype.setting = {
3148
3149        options: {},
3150
3151        speedOptions: {
3152            "head": "速度",
3153            "speed-025":    "0.25",
3154            "speed-05":     "0.5",
3155            "speed-075":    "0.75",
3156            "speed-1":      "正常",
3157            "speed-125":    "1.25",
3158            "speed-15":     "1.5",
3159            "speed-2":      "2"
3160        },
3161        
3162        init: function() {
3163
3164            if (this.disableSetting) {
3165
3166                this.container.find(".h5ToggleSetting").remove();
3167
3168                return;
3169
3170            }
3171
3172            if (!("loadNext" in this.config)) {
3173                this.loadNext = JSON.parse( this.fn.getCookie("h5LoadNext") || true);
3174            }
3175
3176            var setting = this.setting,
3177                ctn     = this.container;
3178
3179            setting.speedOptions.head = text.speed;
3180            // setting.qualityOptions.head = text.quality;
3181            setting.speedOptions['speed-1'] = text.normal;
3182
3183            // setting.options[text.speed]   = text.normal + '<div class="h5ArrowR h5Arrow"></div>';
3184            // setting.options[text.quality] = qualityMapping[this.quality] +'<div class="h5ArrowR h5Arrow"></div>';
3185
3186            setting.changeOption.call(this);
3187
3188            domElem.on.call( window, "mouseup touched", function (){
3189                if (!ctn.find(".h5SettingPlane:hover") && !ctn.find(".h5ToggleSetting:hover")) {
3190                    ctn.removeClass("h5SettingOn");
3191                }
3192            });
3193
3194        },
3195
3196        changeOption: function(options, listener) {
3197
3198            var _this        = this,
3199                html         = '',
3200                setting      = this.setting,
3201                speedReg     = new RegExp('^speed-' + _this.video.playbackRate.toString().replace('.', '') + '$'),
3202                qualityReg   = new RegExp('^quality-' + _this.qual
3202ity.level + '$'),
3203                settingPlane = _this.container.find(".h5SettingPlane");
3204
3205            if ( !_this.h5playerAvailable || _this.disableSetting || !settingPlane ) {
3206                return;
3207            }
3208            
3209            if ( !options ) {
3210
3211                var rate = this.playbackRate;
3212
3213                setting.options = {};
3214
3215                if (!this.disablePlayNext) {
3216                    setting.options[text.autoplay] = ''
3217                        +   '<div class="h5OnOffCtn">'
3218                        +       '<input type="checkbox" '+ (this.loadNext ? "checked" : "") +'>'
3219                        +       '<div class="h5OnOff"></div>'
3220                        +   '</div>';
3221                }
3222
3223                setting.options[text.speed] = (rate==1? text.normal : rate) + '<div class="h5ArrowR h5Arrow"></div>';
3224
3225                // if ( _this.qualities.length ) {
3226                //     if ( !_this.m3u8Video ) {
3227                //         setting.options[text.quality] = this.quality.pixel +'<div class="h5ArrowR h5Arrow"></div>';
3228                //     } else {
3229                //         var _text = this.quality === "auto" ? "自動" : this.hls.levels[this.quality].height + "p";
3230                //         setting.options[text.quality] = _text + '<div class="h5ArrowR h5Arrow"></div>';
3231                //     }
3232                // }
3233                if ( this.qualities.length > 1 ) {
3234                    setting.options[text.quality] = this.quality.pixel +'<div class="h5ArrowR h5Arrow"></div>';
3235                }
3236
3237                options = setting.options;   
3238
3239            }
3240
3241            // options  = options  || this.setting.options;
3242            listener = listener || "";
3243
3244            for (var key in options) {
3245
3246                var className = key.replace(text.autoplay, 'h5PlayNextCtrl')
3247                                    .replace(text.quality, 'h5QualityCtrl')
3248                                    .replace(text.speed, 'h5SpeedCtrl')
3249                                    .replace("head", 'h5OptionHead');
3250
3251                html += '<div class="h5Row ' + className + '"><div class="h5Cell">';
3252                html += key.replace(speedReg, '<div class="h5Tick"></div>')
3253                            .replace(qualityReg, '<div class="h5Tick"></div>')
3254                            .replace(/speed-[0-9]*|quality-[a-z0-9]*/g, '')
3255                            .replace('head', '<div class="h5ArrowL h5Arrow"></div>');
3256                html += '</div><div class="h5Cell">' + options[key] + '</div></div>';
3257
3258            }
3259
3260            settingPlane
3261                .removeClass('speed quality')
3262                .addClass(listener)
3263                .html( html ); 
3264
3265            var height = 0;
3266            each( settingPlane.children , function( v ){
3267                if( v.style.display !== "none" ){
3268                    height += v.offsetHeight || Num( domElem.css.call(v,"height") );
3269                }
3270            });
3271
3272            if( settingPlane.querySelector(".h5OptionHead") ){
3273                height += 5; //margin bottom of .h5OptionHead
3274            }
3275
3276            settingPlane.style.height = height + Num( settingPlane.css("padding-top") ) * 2 + "px";
3277
3278            _this.setting.addListener.call( _this , listener );
3279
3280        },
3281
3282        addListener: function(type) {
3283
3284            var _this        = this,
3285                setting      = this.setting,
3286                video        = this.video,
3287                ctn          = this.container,
3288                settingPlane = ctn.find(".h5SettingPlane");
3289
3290            function qualityChange(evt) {
3291                
3292                var newValue = Array.prototype.indexOf.call(this.parentElement.children, this) - 1;
3293
3294                if (_this.quality.level !== newValue) {
3295
3296                    //record current status
3297                    var curr    = video.currentTime,
3298                        ended   = _this.ended(),
3299                        playing = !video.paused;
3300
3301                    _this.quality = newValue;
3302                    _this.setVideoSrc(_this, function() {
3303
3304                        if (playing || ended) {
3305                            _this.play();
3306                        }
3307
3308                        if( curr > 0 ){
3309                            _this.video.currentTime = ended ? 0 : curr;
3310                        }
3311
3312                    }, {
3313                        force: true
3314                    });
3315
3316                    setting.options[text.quality] = _this.quality.type + "<div class='h5ArrowR h5Arrow'></div>";
3317
3318                }
3319
3320            }
3321
3322            function m3u8QualityChange(evt){
3323
3324                var native = _this.hls.native;
3325                var index = Array.prototype.indexOf.call( this.parentElement.children, this ) - 1;
3326
3327                if ( native ) {
3328
3329                    var temp = _this.video.currentTime;
3330
3331                    _this.video.src = _this.hls.levels[index].url;
3332                    _this.container.addClass("h5Loading");
3333                    _this.video.once("loadedmetadata", _this.play.bind(_this));
3334                    _this.video.once("timeupdate", function(){
3335                        _this.video.currentTime = temp;
3336                    });
3337
3338                } else {
3339                    _this.hls.currentLevel = index - 1;
3340                }
3341
3342                _this.quality = index;
3343
3344                setting.options[text.quality] = _this.quality.type + "<div class='h5ArrowR h5Arrow'></div>";
3345
3346            }
3347
3348            var fn = {
3349
3350                speed: function() {
3351                    _this.playbackRate = this.textContent.replace(text.normal, 1);
3352                    setting.options[text.speed] = _this.playbackRate + "<div class='h5ArrowR h5Arrow'></div>";
3353                    setting.changeOption.call(_this);
3354                },
3355
3356                quality: _this.m3u8Video ? m3u8QualityChange : qualityChange
3357
3358            };
3359
3360            if (fn[type]) {
3361
3362                settingPlane.find(".h5Row").forEach(function(v, k) {
3363
3364                    if (k > 0) {
3365                        v.on("click", fn[type]);
3366                    }
3367
3368                    if (type != "speed" || k === 0) {
3369
3370                        v.on("click", function() {
3371                            setting.changeOption.call(_this);
3372                        });
3373
3374                    }
3375
3376
3377                });
3378
3379            }
3380            else {
3381
3382                var h5PlayNextCtrl = ctn.find(".h5PlayNextCtrl");
3383                var qualityCtrl = settingPlane.find(".h5QualityCtrl");
3384                
3385                h5PlayNextCtrl && h5PlayNextCtrl.on("click", function() {
3386
3387                    _this.loadNext = !_this.loadNext;
3388                    _this.fn.setCookie("h5LoadNext", _this.loadNext);
3389
3390                    this.querySelector("input").checked = _this.loadNext;
3391
3392                });
3393
3394                settingPlane.find(".h5SpeedCtrl").on("click", function() {
3395                    setting.changeOption.call( _this , setting.speedOptions, "speed");
3396                });
3397
3398                
3399                qualityCtrl && qualityCtrl.on("click", function() {
3400                    var options = {head: text.quality};
3401                    _this.qualities.forEach(function(v, k){
3402                        if ( _this.m3u8Video || k < 2 ) {
3403                            options["quality-"+k] = v.pixel;
3404                        }
3405                    });
3406                    setting.changeOption.call( _this, options, "quality");
3407                });
3408
3409            }
3410
3411        },
3412
3413    };
3414
3415    h5Player.prototype.share = {
3416
3417        init: function () {
3418
3419            var _this = this,
3420                ctn = this.container,
3421                h5ShareLayer = ctn.find(".h5ShareLayer");
3422
3423            if (_this.disableShare) {
3424
3425                removeAll(ctn.find('.h5ToggleShare'));
3426
3427                return;
3428            }
3429
3430            h5ShareLayer.html(
3431                '<div class="h5Table">' +
3432                    '<div class="h5CloseLayer h5AbsLayer h5Transparent"><div class="h5Close">&#x2715;</div></div>' +
3433                    '<div class="h5Cell">' +
3434                        '<div class="h5ShareBtnCtn h5Table">' +
3435                            '<div class="h5ShareBtn facebook"><div>Facebook</div></div>' +
3436                            '<div class="h5ShareBtn google"><div>Google</div></div>' +
3437                            '<div class="h5ShareBtn twitter"><div>Twitter</div></div>' +
3438                            '<div class="h5ShareBtn sina"><div>' + text.sina + '</div></div>' +
3439                            '<div class="h5ShareBtn whatsapp"><div>Whatsapp</div></div>' +
3440                            '<div class="h5ShareBtn link"><div>' + text.copyURL2 + '</div></div>' +
3441                        '</div>' + // close h5ShareBtnCtns
3442                    '</div>' + // close cell
3443                '</div>'); //close table
3444
3445            h5ShareLayer.find(".h5CloseLayer").on("click", _this.toggleShare.bind(_this));
3446
3447            h5ShareLayer.find(".h5ShareBtn").forEach(function (v, k) {
3448
3449                if (k < 5) {
3450
3451                    var type = v.className.replace("h5ShareBtn", "").trim();
3452
3453                    v.on('click', function () {
3454                        if (_this.customShareFunction.call(_this, type) !== false) {
3455                            newTab(_this.share.link.call(_this, type), _this);
3456                        }
3457                    });
3458
3459                }
3460                else {
3461
3462                    v.on("click", function () {
3463
3464                        _this.contextMenu.copyToClipboard.call(_this, ctn.find("textarea"));
3465                        this.addClass(_this.copyStatus);
3466                        this.children[0].innerHTML = _this.copyStatus == "success" ? text.copySuccess : text.copyFail;
3467                        this.style.backgroundImage = "url(http://hk.on.cc/module/player/img/" + _this.copyStatus + ".png)";
3468
3469                    });
3470
3471                    v.on("mouseleave", function () {
3472
3473                        this.removeClass("success fail");
3474                        this.children[0].innerHTML = text.copyURL2;
3475                        this.style.backgroundImage = "url(http://hk.on.cc/module/player/img/link.png)";
3476
3477                    });
3478
3479                }
3480
3481            });
3482
3483        },
3484
3485        link: function (type) {
3486
3487            var phpUrl = this.customShareUrl.call(this, type) || this.share.getOntvUrl.call(this, 'php') || '',
3488                dirUrl = this.customShareUrl.call(this, type) || this.share.getOntvUrl.call(this, 'dir') || '',
3489                pic = this.poster,
3490                title = this.title;
3491
3492            this.picHostName = this.picHostName || 'tv.on.cc';
3493            this.shareform = this.shareform || text.ontv;
3494
3495            if (type == "facebook") return 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(phpUrl);
3496            else if (type == "google") return 'https://plus.google.com/share?url=' + encodeURIComponent(phpUrl);
3497            else if (type == "twitter") return 'http://twitter.com/home?status=' + encodeURIComponent(title) + ' ' + encodeURIComponent(dirUrl);
3498            else if (type == "sina") {
3499                var _pic = (/http:|https:/g.test(pic)) ? pic : encodeURIComponent('http://' + this.picHostName + pic);
3500                return 'http://service.weibo.com/share/share.php?url=&title=' + encodeURIComponent(title) + encodeURI('(' + text.shareFrom + ' @' + this.shareform + ') ') + encodeURIComponent(dirUrl) + '&pic=' + _pic;
3501            }
3502            else if (type == "whatsapp") return 'whatsapp://send?text=' + encodeURIComponent(title) + ' ' + encodeURIComponent(phpUrl);
3503            else if (type == 'link') return dirUrl;
3504
3505        },
3506
3507        getOntvUrl: function (type) {
3508
3509            var loc = this.loc || 'hk';
3510
3511            if (type == 'php') {
3512                return 'http://on.cc/onccMainWebapp/videoShare.faces?pub=ontv' + loc + '&pubType=video&shareType=facebook&createTime=' + this.createTime + '&videoId=' + this.videoId;
3513            }
3514            else if (type == 'dir') {
3515                return 'http://tv.on.cc/' + loc + '/index.html?i=' + this.videoId + '&d=' + this.createTime;
3516            }
3517
3518            return '';
3519
3520        },
3521
3522        customURL: function (config) {
3523
3524            config = config || {};
3525            config.url = config.url || window.location.href;
3526            config.title = config.title || this.title;
3527            config.thumbnail = config.thumbnail || this.poster;
3528            config.description = typeof config.description !== "undefined" ? config.description : this.description;
3529
3530            return 'http://hk.on.cc/onccMainWebapp/socialmediashare.faces?' +
3531                'articleUrl=' + config.url +
3532                '&articleTitle=' + config.title +
3533                '&articleImage=' + config.thumbnail +
3534                '&articleDescription=' + config.description;
3535
3536        }
3537
3538    };
3539
3540    h5Player.prototype.svg = {
3541
3542        play: "M 12 26 L 18.5 22 L 18.5 14 L 12 10 Z M 18.5 22 L 25 18 L 25 18 L 18.5 14 Z",
3543        pause: "M 12 26 L 16 26 L 16 10 L 12 10 Z M 21 26 L 25 26 L 25 10 L 21 10 Z",
3544        replay: "M 17,9 C12,9 8,13 8,18 C8,23 12,27 17,27 C19.5,27 21.82,25.95 23.45,24.26 L22.04,22.85 C20.77,24.17 19,25 17,25 C13,25 10,21.86 10,18 C10,14.13 13.13,11 17,11 C20.86,11 24,14 24,18 L21,18 L25,22 L29,18 L26,18 C26,13 22,9 17,9 Z",
3545        high: "M11.016 3.234C15.047 4.125 18 7.734 18 12s-2.953 7.875-6.984 8.766v-2.063c2.906-.844 4.969-3.516 4.969-6.703s-2.063-5.859-4.969-6.703V3.234zM13.5 12a4.451 4.451 0 0 1-2.484 4.031V7.968c1.5.75 2.484 2.25 2.484 4.031zM0 9h3.984L9 3.984v16.031l-5.016-5.016H0v-6z",
3546        low: "M0 9h3.984L9 3.984v16.031l-5.016-5.016H0v-6zm13.5 3c0 1.781-1.031 3.281-2.531 4.031V7.968c1.5.75 2.531 2.25 2.531 4.031z",
3547        muted: "M0 9h4.031L9 3.984v16.031l-4.969-5.016H0v-6z",
3548        off: "M9 3.984v4.219L6.891 6.094zM1.266 3L18 19.734 16.734 21l-2.063-2.063c-1.078.844-2.297 1.5-3.656 1.828v-2.063c.844-.234 1.594-.656 2.25-1.172l-4.266-4.266v6.75l-5.016-5.016H-.001v-6h4.734L-.001 4.264zm14.718 9c0-3.188-2.063-5.859-4.969-6.703V3.234c4.031.891 6.984 4.5 6.984 8.766a8.87 8.87 0 0 1-1.031 4.172l-1.5-1.547A6.901 6.901 0 0 0 15.984 12zM13.5 12c0 .234 0 .422-.047.609l-2.438-2.438V7.968c1.5.75 2.484 2.25 2.484 4.031z",
3549        share: "M16.795 15.259c1.274 0 2.323 1.049 2.323 2.323s-1.049 2.36-2.323 2.36-2.323-1.086-2.323-2.36c0-.187 0-.375.038-.524l-5.657-3.297A2.415 2.415 0 0 1 4.807 12a2.414 2.414 0 0 1 4.046-1.761l5.619-3.259c-.037-.187-.075-.375-.075-.562 0-1.311 1.086-2.398 2.398-2.398s2.398 1.086 2.398 2.398-1.086 2.398-2.398 2.398c-.637 0-1.199-.262-1.648-.674l-5.619 3.297c.038.187.075.375.075.562s-.038.375-.075.562l5.694 3.297a2.342 2.342 0 0 1 1.573-.599z",
3550        setting: "M12 14.811c1.537 0 2.811-1.275 2.811-2.811S13.536 9.189 12 9.189 9.189 10.464 9.189 12s1.275 2.811 2.811 2.811zm5.96-2.024l1.687 1.312c.15.112.187.337.
3550075.525l-1.612 2.774c-.112.187-.3.225-.487.15l-1.987-.787c-.412.3-.862.6-1.349.787l-.3 2.099c-.037.187-.187.337-.375.337h-3.224c-.187 0-.337-.15-.375-.337l-.3-2.099a4.89 4.89 0 0 1-1.349-.787l-1.987.787c-.187.075-.375.038-.487-.15l-1.612-2.774c-.112-.187-.075-.412.075-.525l1.687-1.312c-.038-.262-.038-.525-.038-.787s0-.525.038-.787L4.353 9.901c-.15-.112-.187-.337-.075-.525L5.89 6.602c.112-.187.3-.225.487-.15l1.987.787c.412-.3.862-.6 1.349-.787l.3-2.099c.037-.187.187-.337.375-.337h3.224c.187 0 .337.15.375.337l.3 2.099c.487.187.937.45 1.349.787l1.987-.787c.187-.075.375-.038.487.15l1.612 2.774c.112.187.075.412-.075.525l-1.687 1.312c.038.262.038.525.038.787s0 .525-.038.787z",
3551        fullscreen: "M14.304 4.016h5.68v5.68h-2.251v-3.43h-3.43V4.015zm3.43 13.718v-3.43h2.251v5.68h-5.68v-2.251h3.43zM4.016 9.696v-5.68h5.68v2.251h-3.43v3.43H4.015zm2.25 4.608v3.43h3.43v2.251h-5.68v-5.68h2.251z",
3552        exitFullScreen: "M16.555 7.445h3.43v2.251h-5.68v-5.68h2.251v3.43zm-2.251 12.539v-5.68h5.68v2.251h-3.43v3.43h-2.251zM7.445 7.445v-3.43h2.251v5.68h-5.68V7.444h3.43zm-3.429 9.11v-2.251h5.68v5.68H7.445v-3.43h-3.43z",
3553        news : "M16.625 1.5h-12.25q-1.087 0-1.856 0.769t-0.769 1.856v15.75q0 1.087 0.769 1.856t1.856 0.769h12.25q1.087 0 1.856-0.769t0.769-1.856v-15.75q0-1.087-0.769-1.856t-1.856-0.769zM14 16.375h-7q-0.362 0-0.619 0.256t-0.256 0.619 0.256 0.619 0.619 0.256h7q0.362 0 0.619-0.256t0.256-0.619-0.256-0.619-0.619-0.256zM14 12.875h-7q-0.362 0-0.619 0.256t-0.256 0.619 0.256 0.619 0.619 0.256h7q0.362 0 0.619-0.256t0.256-0.619-0.256-0.619-0.619-0.256zM4.375 3.25h12.25q0.362 0 0.619 0.256t0.256 0.619v15.75q0 0.362-0.256 0.619t-0.619 0.256h-12.25q-0.362 0-0.619-0.256t-0.256-0.619v-15.75q0-0.362 0.256-0.619t0.619-0.256zM14 9.375h-7q-0.362 0-0.619 0.256t-0.256 0.619 0.256 0.619 0.619 0.256h7q0.362 0 0.619-0.256t0.256-0.619-0.256-0.619-0.619-0.256zM14 5.875h-3.5q-0.362 0-0.619 0.256t-0.256 0.619 0.256 0.619 0.619 0.256h3.5q0.362 0 0.619-0.256t0.256-0.619-0.256-0.619-0.619-0.256z",
3554        
3555        get: function(pathName) {
3556
3557            var fill = "#fff";
3558
3559            return '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24"><path fill="' + fill + '" d="' + this.svg[pathName] + '"></path></svg>';
3560
3561        },
3562
3563        playIcon : {
3564
3565            set : function(status){
3566
3567                if ( !this.h5playerAvailable ) {
3568                    return;
3569                }
3570
3571                var ctn = this.container;
3572
3573                ctn.find(".h5PlayPause svg path").setAttribute("d", this.svg[status]);
3574                ctn.removeClass("h5Playing h5Paused h5Ended").addClass(({
3575                    play : "h5Paused",
3576                    pause : "h5Playing",
3577                    replay : "h5Ended"
3578                })[status]);
3579
3580            },
3581            html : function(){
3582                return '<svg class="h5PlayIcon" height="100%" viewBox="0 0 36 36">' +
3583                            '<use xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></use>'+
3584                            '<path d="'+ this.svg.play +'"></path>'+
3585                        '</svg>';
3586            }
3587
3588        },
3589
3590        spinner : function(){
3591
3592            var stroke      = "rgba(255, 255, 255, 1)",
3593                strokeWidth = 3;
3594
3595            return '<div class="h5Spinner">' +
3596                        '<svg width="50" height="50" viewBox="0 0 44 44">' +
3597                            '<circle cx="22" cy="22" r="20" fill="none" stroke="'+ stroke +'" stroke-width="'+ strokeWidth +'" stroke-dasharray="90,150" stroke-dashoffset="-35"></circle>'+
3598                        '</svg>'+
3599                    '</div>';
3600
3601        }
3602
3603    };
3604
3605    h5Player.prototype.videoAd = {
3606
3607        adURL : "",
3608        prerollURL: 'http://ad4.on.cc/web/www/delivery/fc.php?script=bannerTypeHtml:vastInlineBannerTypeHtml:vastInlineHtml&zones=pre-roll0-0%3D446&nz=1&source=&r=R0.7950630043633282&block=1&format=vast&charset=UTF-8',
3609        backupURL: 'http://ad4.on.cc/web/www/delivery/fc.php?script=bannerTypeHtml:vastInlineBannerTypeHtml:vastInlineHtml&zones=pre-roll0-0%3D827&nz=1&source=&r=R0.7950630043633282&block=1&format=vast&charset=UTF-8',
3610        mobileURL : 'http://datafeed.on.cc/ad7/mobile/www/delivery/fc.php?script=bannerTypeHtml:vastInlineBannerTypeHtml:vastInlineHtml&zones=pre-roll0-0%3D2172&nz=1&source=&r=R0.7950630043633282&block=1&format=vast&charset=UTF-8',
3611        postrollURL : 'http://ad4.on.cc/web/www/delivery/fc.php?script=bannerTypeHtml:vastInlineBannerTypeHtml:vastInlineHtml&zones=pre-roll0-0%3D942&nz=1&source=&r=R0.7950630043633282&block=1&format=vast&charset=UTF_8',
3612        ad4EmptyURL :'http://ad4.on.cc/web/www/delivery/fc.php?script=bannerTypeHtml:vastInlineBannerTypeHtml:vastInlineHtml&zones=pre-roll0-0%3D{{zoneId}}&nz=1&source=&r=R0.7950630043633282&block=1&format=vast&charset=UTF-8',
3613
3614        init: function( type ) {
3615
3616            type = type || "preroll";
3617
3618            var _this   = this,
3619                ctn     = this.container,
3620                videoAd = this.videoAd;
3621                        
3622            if (
3623                !this.h5playerAvailable || 
3624                ( !this.enableVideoAd.postroll && this.ended() ) ||
3625                ( !this.enableVideoAd.preroll && this.video.currentTime === 0 ) )
3626            {
3627                this.adCompleted = true;
3628                videoAd.ready.call(this);
3629                return;
3630            }
3631
3632            if( type === "preroll" && this.mobile ){
3633                type = "mobile";
3634            }
3635
3636            if( type === "postroll" ){
3637                _this.backupAdLoaded = true; //postroll 唔用backup
3638                _this.postrollAdLoaded = true;
3639                _this.adCompleteCallbacks.push(function(){
3640
3641                    // var dot = ctn.find(".h5ProgressBarCtn .h5Dot");
3642
3643                    // ctn.find(".h5ProgressBar").css("width","100%");
3644                    // dot.css("left","calc(100% - "+ dot.clientWidth/2 +"px)");
3645
3646                    _this.playNext.init.call(_this);
3647                    _this.svg.playIcon.set.call(_this,"replay");
3648
3649                });
3650            }
3651
3652            this.pause();
3653
3654            this.adReady            = false;
3655            this.adCompleted        = false;
3656            this.tracking.event  = {};
3657            videoAd.outputurl       = "";
3658
3659            videoAd.adURL = videoAd[type+"URL"];
3660
3661            ctn.addClass("h5Loading");
3662
3663            clearTimeout( this.adLoadingTimeOut );
3664
3665            this.adLoadingTimeOut = setTimeout( function(){
3666
3667                log("adLoadingTimeOut");
3668
3669                videoAd.ready.call(_this);
3670                videoAd.stopAd.call(_this);
3671
3672            }, 5000);
3673
3674            videoAd.loadAdXML.call( _this, videoAd.adURL );
3675
3676            
3677
3678        },
3679
3680        loadAdXML: function(url) {
3681
3682            var _this   = this,
3683                videoAd = this.videoAd;
3684
3685            url = url.replace("http://ad6.on.cc/", "http://datafeed.on.cc/ad6/");
3686
3687            log("request ad xml:", url);
3688
3689            _this.fn.loadXML(url, videoAd.checkAdXML.bind(_this), function() {
3690
3691                //error callback
3692
3693                log( "loading video ad xml failed, " + (url==="" ? "url is empty":"url:" + url)  );
3694            
3695                if ( _this.ended() || _this.backupAdLoaded ) {
3696                    videoAd.complete.call(_this);
3697                } else {
3698                    videoAd.empty.call(_this);
3699                }
3700
3701            });
3702
3703        },
3704
3705        checkAdXML: function(xml) {
3706
3707            var _this   = this,
3708                videoAd = this.videoAd;
3709            
3710            var adParameter = xmlTextParse(xml.querySelector("AdParameters") || '{}' );
3711            var tempURL = videoAd.outputurl;
3712
3713            try {
3714                adParameter = JSON.parse(adParameter);
3715            } catch(err) {
3716                adParameter = {};
3717            }
3718
3719            function parseMediaFile(xml){
3720
3721                return map(xml.querySelectorAll("MediaFile"), function(v, k) {
3722                    
3723                    var attrs = v.attributes;
3724                    var result = {};
3725                    for (var i=0; i<attrs.length; i++) {
3726                        var attr = attrs[i];
3727                        result[attr.name] = attr.value;
3728                    }
3729
3730                    result.url = xmlTextParse(v.querySelector('url') || v.querySelector('URL') || v);
3731
3732                    return result;
3733   
3734                });
3735
3736            }
3737
3738            videoAd.tracking.get.call( _this , xml );
3739
3740            if ( adParameter.pixels ) {
3741
3742                if ( !Array.isArray(_this.tracking.event.impression) ){
3743                    _this.tracking.event.impression = []
3744                }
3745
3746                adParameter.pixels.forEach(function(v){
3747                    _this.tracking.event.impression.push(v);
3748                })
3749
3750                
3751            }
3752            
3753            if( !_this.tracking.event.impression && videoAd.adURL.indexOf("fc.php") !== -1 && !xml.querySelector("VAST") ){
3754
3755                var param = !_this.mobile ? "bannerid=4270&campaignid=2139" : "bannerid=13172&campaignid=7142";
3756                
3757                _this.tracking.event.impression = [
3758                    videoAd.adURL.split("?")[0].replace("fc.php","lg.php") + "?"+ param +"&zoneid=" + videoAd.adURL.split("&")[1].split("%3D")[1]
3759                ];
3760
3761            }
3762
3763            videoAd.tracking.load.call( _this , "impression" );
3764            videoAd.tracking.load.call( _this , "creativeView" );
3765
3766            if (xml.querySelector("Ad")) {
3767
3768                if ( adParameter.sources ) {
3769
3770                    if ( adParameter.sources[0].mimetype === "application/xml" ) {
3771                        videoAd.outputurl = adParameter.sources[0].url;
3772                    }
3773
3774                } else if (xml.querySelector("Wrapper")) {
3775
3776                    each(xml.querySelectorAll("VASTAdTagURI"), function(v, k) {
3777                        videoAd.outputurl = xmlTextParse(v);
3778                    });
3779
3780                }
3781                else if (xml.querySelector("Creatives")) {
3782                    
3783                    each(xml.querySelectorAll("Creatives"), function(v, k) {
3784
3785                        if (v.querySelector("Linear")) {
3786
3787                            var mediaFiles = parseMediaFile(xml);
3788                            var outputurl = "";
3789
3790                            for (var index in mediaFiles) {
3791                                if ( (mediaFiles[index].type || "").indexOf("video/mp4") !== -1 ) {
3792                                    outputurl = mediaFiles[index].url;
3793                                    break;
3794                                }
3795                            }
3796
3797                            if ( !outputurl ) {
3798                                outputurl = mediaFiles[0].url;
3799                            }
3800
3801                            videoAd.outputurl = outputurl;
3802                    
3803                        }
3804
3805                    });
3806
3807                }
3808                else {
3809
3810                    videoAd.outputurl = parseMediaFile(xml)[0].url;
3811
3812                }
3813
3814                if (videoAd.outputurl){
3815
3816                    if ( tempURL && /\.js|\.swf/.test(videoAd.outputurl) && !/stickyad/.test(videoAd.outputurl) ) {
3817                        videoAd.outputurl = tempURL;
3818                    }
3819
3820                    videoAd.load.call(_this, videoAd.outputurl, adParameter);
3821
3822                }
3823 
3824
3825            }
3826            else if( _this.mobile ){
3827
3828                videoAd.empty.call(_this);
3829
3830            } else {
3831
3832                videoAd.backupAd.call(_this);
3833
3834            }
3835
3836        },
3837
3838
3839        load : function(url, param){
3840
3841            var _this   = this,
3842                videoAd = this.videoAd;
3843
3844            // var js = /\.js/.test(url),
3845            var stickyad = /\.stickyad/.test(url) && /\/mustang\//.test(url),
3846            // var stickyad = /\.stickyad/.test(url),
3847                zoneId = /zoneId/.test(url),
3848                _googleAd = /google|pubads.g.doubleclick.net|rubiconproject|s.yimg.com/.test(url),
3849                innovid = /innovid/.test(url),
3850                doubleclickAd = /ad.doubleclick/.test(url),
3851                btrll = /btrll.com/.test(url);
3852                // apiFramework = v1.getAttribute("apiFramework"),
3853                // type = v1.getAttribute("type");
3854
3855
3856            function failToLoadSDK(){
3857                console.log("loading Ad vendor SDK fail");
3858                if (_this.ended()) {
3859                    videoAd.complete.call(_this);
3860                } else {
3861                    videoAd.empty.call(_this);
3862                }
3863            }    
3864
3865            if (/\.MP4/i.test(url)) {
3866                
3867                // if( Number(v1.getAttribute('width')) <= 640 ){
3868                    _this.itvcSrcURL = url;
3869                // }
3870
3871                videoAd.itvc.init.call(_this);
3872                
3873            }
3874            else if (stickyad && zoneId ){
3875
3876                if (_this.iOS) {
3877                    videoAd.empty.call(_this);
3878                    log("stop ad as ios device not support");
3879                    return;
3880                }
3881
3882                log( "videoAd vendor : stickyAds" );
3883
3884                // 東網m版有com.greensock 所以要先check window.com
3885                var stickyAdSdkExist = !window.com ? false : com.stickyadstv ? true : false;
3886
3887                if (stickyAdSdkExist) {
3888
3889                    videoAd.stickyAds.init.call( _this , url);
3890
3891                }
3892                else {
3893
3894                    _this.fn.loadScript(videoAd.stickyAds.sdk, function() {
3895
3896                        videoAd.stickyAds.init.call( _this , url);
3897
3898                    }, failToLoadSDK );
3899
3900                }
3901
3902            }
3903            else if ( doubleclickAd || innovid || _googleAd ) {
3904
3905                if (_this.iOS) {
3906                    videoAd.empty.call(_this);
3907                    log("stop ad as ios device not support");
3908                    return;
3909                }
3910
3911                // var adsystem = xml.querySelector("AdSystem") || {
3912                //     textContent : "google ima sdk used"
3913                // }
3914
3915                // log( "VideoAd Vendor : " + adsystem.textContent );
3916
3917
3918                var config = {
3919                    // hidetimeline : _googleAd || btrll,
3920                    skip : !_googleAd
3921                };
3922
3923                try {
3924
3925                    videoAd.googleAd.init.call( _this , url, config);
3926
3927                }
3928                catch (error) {
3929
3930                    _this.fn.loadScript(videoAd.googleAd.sdk, function() {
3931
3932                        removeAll( _this.container.find(".h5GoogleAdCtn") );
3933
3934                        videoAd.googleAd.init.call( _this , url, config);
3935
3936                    }, failToLoadSDK );
3937
3938                }
3939
3940            } else if ( param.mediaFiles ) {
3941
3942                if ( param.mediaFiles.length ) {
3943
3944                    var indexOfMaxValue = param.mediaFiles.reduce(function(iMax, x, i, arr){
3945                        return x.bitrate > arr[iMax].bitrate ? i : iMax
3946                    }, 0);
3947
3948                    _this.itvcSrcURL = param.mediaFiles[indexOfMaxValue].value;
3949                    videoAd.itvc.init.call(_this);
3950
3951                } else {
3952
3953                    try {
3954
3955                        videoAd.googleAd.init.call( _this , url, {
3956                            skip : true
3957                        });
3958
3959                    }
3960                    catch (error) {
3961
3962                        _this.fn.loadScript(videoAd.googleAd.sdk, function() {
3963
3964                            removeAll( _this.container.find(".h5GoogleAdCtn") );
3965
3966                            videoAd.googleAd.init.call( _this , url, {
3967                                skip : true
3968                            });
3969
3970                        }, failToLoadSDK );
3971
3972                    }
3973
3974                }
3975
3976                
3977            } else {
3978                videoAd.loadAdXML.call( _this , url );
3979            }
3980
3981        },
3982
3983        empty : function(){
3984            this.adCompleted = true;
3985            this.videoAd.ready.call(this);
3986            this.container.removeClass("h5Loading");
3987        },
3988
3989        ready : function() {
3990
3991            log( "ad ready" );
3992
3993            clearTimeout(this.adLoadingTimeOut);
3994
3995            this.adReady = true;
3996            this.pause();
3997
3998            var play = this.play.bind(this);
3999
4000            if ( this.autoplay ) {
4001                if (!this.ended()) {
4002                    play(function(){
4003                        if ( this.mobile ) {
4004                            this.muted = true;
4005                        }
4006                        play(function(){
4007                            this.container.removeClass("h5Loading");
4008                        });
4009                    });
4010                }
4011            } 
4012            else {
4013                this.container.removeClass("h5Loading");
4014            }
4015
4016
4017        },
4018
4019        error : function(){
4020
4021            // var videoAd = this.videoAd;
4022
4023            clearInterval(this.skipCountDown);
4024            clearTimeout(this.adLoadingTimeOut);
4025
4026            this.adReady     = true;
4027            this.adCompleted = true;
4028
4029            removeAll( this.container.find(".h5SkipAdBtn") );
4030
4031            this.container.removeClass("h5PlayingAd h5Loading h5HideCtrl");
4032            // this.container.removeClass("h5PlayingAd h5Loading h5HideCtrl h5HideTimeLine");
4033
4034        },
4035
4036        complete : function(){
4037
4038            log("ad complete");
4039
4040            var videoAd = this.videoAd;
4041
4042            videoAd.error.call(this);
4043
4044            if( !this.ended() ){
4045
4046                this.updateProgressBar();
4047                this.play();
4048                
4049            }
4050
4051            // this.container.removeClass("h5PlayingAd h5Loading h5HideCtrl h5HideTimeLine");
4052
4053            this.adCompleteCallbacks.forEach(function( callback ){
4054                if (typeof callback === "function") {
4055                    callback();
4056                }
4057            });
4058
4059            this.adCompleteCallbacks = [];
4060
4061        },
4062
4063        stopAd: function() {
4064
4065            // if( !this.adPlaying() ) return;
4066
4067            log( "stop ad" );
4068
4069            var videoAd  = this.videoAd,
4070                stickyAd = videoAd.stickyAds,
4071                googleAd = videoAd.googleAd;
4072                // stickyAd = videoAd.stickyAds,
4073                // googleAd = ctn.find(".h5GoogleAdCtn");
4074
4075            if (stickyAd.adsComponent) {
4076                stickyAd.complete.call(this);
4077            }
4078
4079            if (googleAd.adsManager||googleAd.adsLoader) {
4080                googleAd.complete.call(this);
4081            }
4082
4083            if( this.container.find(".h5ItvcContainer") ){
4084            // if( this.itvcSrcURL ){
4085                videoAd.itvc.complete.call(this);
4086            }
4087
4088            this.adCompleted = true;
4089           
4090            // this.container.removeClass("h5Loading");
4091
4092        },
4093
4094        resize : function( fullscreen ){
4095
4096            if( !this.adPlaying() ) return;
4097
4098            var ctn      = this.container,
4099                stickyAd = this.videoAd.stickyAds.adsComponent,
4100                googleAd = this.videoAd.googleAd.adsManager,
4101                width    = this.video.clientWidth || Num(ctn.css("width")),
4102                height   = this.video.clientHeight || Num(ctn.css("height"));
4103
4104            if (stickyAd) {
4105                stickyAd.onAdContainerSizeChanged(width, height);
4106            }
4107
4108            if (googleAd) {
4109                googleAd.resize(width, height, google.ima.ViewMode.FULLSCREEN);
4110            }
4111
4112        },
4113
4114        backupAd: function() {
4115
4116            var _this   = this,
4117                videoAd = this.videoAd;
4118
4119            if( !this.backupAdLoaded && !this.mobile ){
4120
4121                log( "load backup Ad" );
4122
4123                this.backupAdLoaded = true;
4124
4125                _this.adCompleteCallbacks.push(function(){
4126                    _this.backupAdLoaded = false;
4127                });
4128
4129                videoAd.error.call(this);
4130                videoAd.init.call(this,"backup");
4131
4132            } else if (this.ended()){
4133
4134                // this for postroll error
4135                videoAd.complete.call(this);
4136
4137            } else {
4138
4139                videoAd.error.call(this);
4140                videoAd.ready.call(this);
4141
4142            }
4143
4144        },
4145
4146        skipBtn : {
4147
4148            create : function(skipCallback){
4149
4150                removeAll( this.container.find(".h5SkipAdBtn") );
4151
4152                clearInterval(this.skipCountDown);
4153
4154                this.skipCountDown = setInterval(this.videoAd.skipBtn.update.bind( this , skipCallback), 1000);
4155
4156                this.video.parent()
4157                    .append('<div class="h5SkipAdBtn">' + text.skip1 + '<span>&nbsp;' + this.skipAdTime + '&nbsp;</span>' + text.skip2 + '</div>');
4158
4159            },
4160
4161            update : function(skipCallback){
4162                var btn  = this.container.find(".h5SkipAdBtn span"),
4163                    curr = Number(btn.textContent);
4164                if( curr === 1 ){
4165                    this.videoAd.skipBtn.end.call(this,skipCallback);
4166                }else{
4167                    if( btn ) btn.textContent = ' ' + (curr - 1) + ' ';
4168                }
4169            },
4170
4171            end : function(skipCallback){
4172                skipCallback = skipCallback || noop;
4173                clearInterval(this.skipCountDown);
4174                this.container
4175                    .find(".h5SkipAdBtn")
4176                        .html(text.skip)
4177                        .css("cursor","pointer")
4178                        .on("click", function() {
4179                            skipCallback();
4180                            this.remove();
4181                        });
4182            }
4183
4184        },
4185
4186        tracking : {
4187
4188            event : {},
4189
4190            get : function( xml ){
4191
4192                var _this = this,
4193                    videoAd = this.videoAd;
4194
4195                ["Tracking", "Impression", "ClickTracking"].forEach(function(v, k) {
4196
4197                    each(xml.querySelectorAll(v), function(v1, k1) {
4198
4199                        function lowerFirstLetter(string) {
4200                            return string.charAt(0).toLowerCase() + string.slice(1);
4201                        }
4202
4203                        var URL  = v1.querySelector("URL"),
4204                            name = /Impression|ClickTracking/i.test(v) ? lowerFirstLetter(v1.tagName) : v1.getAttribute("event");
4205                        
4206                        _this.tracking.event[name] = _this.tracking.event[name] || [];
4207
4208                        if (URL) {
4209                            _this.tracking.event[name].push(xmlTextParse(URL));
4210                        }
4211                        else {
4212                            _this.tracking.event[name].push(xmlTextParse(v1));
4213                        }
4214
4215                    });
4216
4217                });
4218
4219                ["clickThroughURL", "clickThrough", "ClickThrough"].forEach(function(v, k) {
4220
4221                    each(xml.querySelectorAll(v), function(v1, k1) {
4222                        
4223                        _this.clickThroughURL = xmlTextParse(v1.querySelector("URL")) || xmlTextParse(v1);
4224
4225                    });
4226
4227                });
4228
4229            },
4230
4231            check : function( val ){
4232
4233                var _this    = this,
4234                    currTime = val.currentTime,
4235                    duration = val.duration,
4236                    status   = '';
4237
4238                if (currTime >= duration) status = 'complete';
4239                else if (currTime >= duration * 0.75) status = 'thirdQuartile';
4240                else if (currTime >= duration * 0.5) status = 'midpoint';
4241                else if (currTime >= duration * 0.25) status = 'firstQuartile';
4242                else if (currTime > 0) status = 'start';
4243
4244                _this.videoAd.tracking.load.call( _this , status );
4245
4246            },
4247
4248            load : function( name ){
4249
4250                var _this    = this;
4251                var events = _this.tracking.event[name];
4252                if (events) {
4253
4254                    events.forEach(function( val ){
4255                        var hitImage = new Image();
4256                        hitImage.src = val;
4257                        if (/h5player_tracking/.test(window.location.href)) {
4258                            console.info(name+" : " + val);
4259                        }
4260                    });
4261
4262                    delete _this.tracking.event[name];
4263                }
4264
4265            }
4266
4267        },
4268
4269        itvc: {
4270
4271            init: function() {
4272
4273                log( "itvc init" );
4274
4275                var _this     = this,
4276                    video     = this.video,
4277                    ctn       = this.container,
4278                    videoAd   = this.videoAd,
4279                    container = createElement("div","h5ItvcContainer"),
4280                    refObj    = ctn.find(".h5LoadingLayer"),
4281                    volBtn    = ctn.find(".h5VolumeBtn"),
4282                    tempCurr  = 0,
4283                    itvcVideo = videoAd.itvc.video = createElement("video"),
4284                    playBtn   = ctn.find(".h5PlayPause"),
4285                    playLayer = ctn.find(".h5PlayPauseLayer");
4286
4287                removeAll( ctn.find(".h5ItvcContainer") );
4288
4289                clearTimeout( this.adLoadingTimeOut );
4290
4291                container.append(itvcVideo);
4292
4293                refObj.before( container );
4294
4295                function play(callback) {
4296                    _this.play.call({
4297                        video: itvcVideo
4298                    }, callback);
4299                }
4300
4301                function toggleMute(){
4302                    if( ctn.find(".h5ItvcContainer") && ctn.find('.h5ControlsBar').css("opacity") === "1" ){
4303                        itvcVideo.muted = !itvcVideo.muted;
4304                    }
4305                }
4306
4307                function complete() {
4308
4309                    delete this.itvcSrcURL;
4310                    
4311                    video.off("play", onplay);
4312                    volBtn.off("click", toggleMute);
4313                    playBtn.off("click", onplay)
4314                    playLayer.off("click", onplay)
4315                    itvcVideo.off();
4316
4317                    removeAll( ctn.find(".h5ItvcContainer") );
4318                    
4319                    videoAd.complete.call(_this);
4320
4321                }  
4322
4323                function onplay(evt){
4324
4325                    _this.pause();
4326
4327                    playLayer.off("click", onplay)
4328                    playBtn.off("click", onplay)
4329                    video.off("play", onplay);
4330
4331                    ctn.addClass("h5PlayingAd");
4332
4333                    var url = _this.clickThroughURL;
4334
4335                    itvcVideo
4336                        .css("cursor","pointer")
4337                        .on(_this.touchable ? "touchend" : "click",function() {
4338
4339                            if (url) {
4340                                newTab(url, 
4341                                    itvcVideo,
4342                                    videoAd.skipBtn.end.bind( _this, complete ) );
4343                            }
4344
4345                            videoAd.tracking.load.call(_this, "clickTracking")
4346                            
4347                        });
4348
4349                    delete _this.clickThroughURL;
4350
4351                    itvcVideo.on("timeupdate",function(){
4352
4353                        if (ctn.find(".h5ItvcContainer video") === itvcVideo) {
4354
4355                            if (!itvcVideo.seeking) {
4356                                tempCurr = itvcVideo.currentTime;
4357                            }
4358
4359                            videoAd.tracking.check.call(_this, this);
4360
4361                            ctn.removeClass("h5Loading");
4362
4363                        } else { 
4364
4365                            log("itvc ad stop");
4366                            video.off("play", onplay);
4367                            itvcVideo.off();
4368                            itvcVideo.pause();
4369
4370                        }
4371
4372                    },true);
4373
4374                    itvcVideo.on("seeking",function(){
4375                        // prevent video ad skip by user
4376                        if( this.currentTime > tempCurr ){
4377                            this.currentTime = tempCurr;
4378                        }
4379                    });
4380
4381                    itvcVideo.on("waiting seeking", ctn.addClass.bind(ctn, "h5Loading"));
4382
4383                    itvcVideo.on("playing", ctn.removeClass.bind(ctn, "h5Loading"));
4384
4385                    itvcVideo.once("play", videoAd.skipBtn.create.bind( _this , complete ));
4386
4387                    if( _this.mobile ){
4388
4389                        volBtn
4390                            .on("click", toggleMute)
4391                            .html( _this.svg.get.call( _this , "off") );
4392
4393                        itvcVideo.muted = true;
4394                        
4395                        itvcVideo.on("volumechange",(function adVolChange(){
4396                            _this.muted = itvcVideo.muted;
4397                            volBtn.innerHTML = _this.svg.get.call( _this , itvcVideo.muted ? "off" : "high" );
4398                            return adVolChange;
4399                        }()));
4400
4401                    }
4402
4403                    itvcVideo.on("ended", complete);
4404
4405                    itvcVideo.once("loadedmetadata",function loaded() {
4406
4407                        play(function(){
4408                            itvcVideo.muted = true;
4409                            play(function(){
4410                                ctn.find(".h5ItvcContainer").after('<div class="h5AbsLayer h5Transparent"><div class="h5AdPlayBtn">'+ _this.svg.playIcon.html.call(_this) +'</div></div>');
4411                                ctn.find(".h5AdPlayBtn").on("click",function(){
4412                                    removeAll(this);
4413                                    itvcVideo.play();
4414                                });
4415                            })
4416                        });
4417                        
4418                    });
4419
4420                    itvcVideo.load();
4421                    
4422                    if( _this.iOS ){
4423                        video.webkitExitFullscreen();
4424                    }
4425
4426                }
4427
4428                itvcVideo.controls = false;
4429                itvcVideo.muted    = _this.muted;
4430                itvcVideo.volume   = _this.volume;
4431                itvcVideo.src      = _this.itvcSrcURL; 
4432                itvcVideo.setAttribute('playsinline', 'true');
4433                
4434                if (_this.ended()){
4435                    onplay();
4436                } else {
4437                    playBtn.on("click", onplay)
4438                    playLayer.on("click", onplay)
4439                    video.on("play", onplay);
4440                }
4441                
4442                videoAd.itvc.complete = complete;
4443                videoAd.ready.call(_this);        
4444
4445            },
4446
4447            complete : function(){
4448                
4449    
4450            }
4451
4452        },
4453
4454        stickyAds: {
4455
4456            sdk : 'http://cdn.stickyadstv.com/mustang/mustang.min.js',
4457
4458            init: function(url) {
4459
4460                var _this       = this,
4461                    videoAd     = this.videoAd,
4462                    video       = this.video,
4463                    ctn         = this.container,
4464                    creative    = url.substr(url.indexOf('zoneId') + 7, url.length).split("&")[0],
4465                    // progressBar = ctn.find(".h5ProgressBar"),
4466                    refObj      = ctn.find(".h5PlayPauseLayer") || video,
4467                    adContainer = createElement("div","h5StickyAdCtn"),
4468                    duration    = 0,
4469                    clickThroughDiv,
4470                    adsComponent,
4471                    adVideo;
4472
4473                function showPlayBtn(){
4474
4475                   //this function for Android , show play button
4476                    var playBtn = createElement("div","h5AdPlayBtn");
4477
4478                    playBtn
4479                        .html(_this.svg.playIcon.html.call( _this ))
4480                        .on("click", function() {
4481                            ctn.find(".h5StickyAdCtn video").play();
4482                            playBtn.remove();
4483                            clickThroughDivFn();
4484                        });
4485
4486                    ctn.find(".h5StickyAdCtn").appendChild(playBtn);
4487
4488                }
4489
4490                function clickThroughDivFn() {
4491                    clickThroughDiv = setInterval(function() {
4492                        var target = document.querySelector('body > .stickyads-overlay'); // clickThrough layer
4493                        if (target) {
4494                            adContainer.appendChild(target);
4495                        }else{
4496                            clearInterval(clickThroughDiv);
4497                        }
4498
4499                    }, 1000);
4500                }
4501
4502                function createAdsComponent(){
4503
4504                    adsComponent = new com.stickyadstv.AdsComponent({
4505
4506                        player: {
4507                            playerWidth: video.clientWidth,
4508                            playerHeight: video.clientHeight
4509                        },
4510                        ads: {
4511                            zones: {
4512                                preroll: creative,
4513                                midroll: "-1",
4514                                postroll: "-1"
4515                            }
4516                        }
4517
4518                    });
4519
4520                }
4521
4522                log("stickyAds init");
4523                log("stickyAds zoneId: " + creative);
4524
4525                clearTimeout( _this.adLoadingTimeOut );
4526
4527                // for IE
4528                try { createAdsComponent(); }
4529                catch (error) { createAdsComponent(); }
4530
4531                adContainer.className = "h5StickyAdCtn";
4532
4533                refObj.before(adContainer);
4534
4535                function onpause() {
4536                    videoAd.stickyAds.adsComponent.onPlayerStateChanged(com.stickyadstv.AdsComponent.PLAYER_PAUSE);
4537                }
4538                function onplay() {
4539                    ctn.addClass("h5Loading");
4540
4541                    if( _this.iOS ){
4542                        video.webkitExitFullscreen();
4543                    }
4544
4545                    videoAd.stickyAds.adsComponent.onPlayerStateChanged(com.stickyadstv.AdsComponent.PLAYER_PLAY);
4546                }
4547
4548                video
4549                    .on("pause", onpause, false)
4550                    .on("play", onplay, false);
4551
4552                _this.adCompleteCallbacks.push(function(){
4553                    video
4554                        .off("pause", onpause, false)
4555                        .off("play", onplay, false);
4556                })
4557
4558                adsComponent.on(com.stickyadstv.AdsComponent.AD_LOADED, function(e) {
4559
4560                    adVideo = ctn.find(".h5StickyAdCtn video");
4561
4562                    ctn.addClass("h5PlayingAd");
4563
4564                    if (ctn.hasClass('h5FullScreen')){
4565                        videoAd.stickyAds.adsComponent.onAdContainerSizeChanged(screen.width, screen.height);
4566                    }
4567
4568                    _this.pause();
4569                    // _this.updateProgressBar();
4570
4571                    if (_this.mobile) {
4572
4573                        var callback = noop;
4574
4575                        if( _this.iOS ){
4576                            video.webkitExitFullscreen();
4577                        }else{
4578
4579                            adVideo.on("play",function _skipBtn(){
4580                                adVideo.off( "play", _skipBtn );
4581                                videoAd.skipBtn.create.call( _this , videoAd.stickyAds.complete.bind(_this));
4582                            });
4583
4584                            callback = showPlayBtn;
4585
4586                        }
4587
4588                        _this.play.call({
4589                            video: ctn.find(".h5StickyAdCtn video")
4590                        } , callback );
4591
4592
4593                    }
4594                    else {
4595                        videoAd.skipBtn.create.call( _this , videoAd.stickyAds.complete.bind(_this));
4596                    }
4597
4598                });
4599
4600                adsComponent.on(com.stickyadstv.AdsComponent.AD_CREATE, function(e) {
4601                    adContainer.appendChild(document.querySelector('body > .stickyads-overlay'));
4602                });
4603
4604                adsComponent.on(com.stickyadstv.AdsComponent.AD_START, function(e) {
4605
4606                    // if( progressBar ){
4607                    //     progressBar.addClass("h5Transition");
4608                    // }
4609
4610                    adsComponent.onVolumeLevelChanged(_this.muted ? 0 : _this.volume);
4611
4612                    clickThroughDivFn();
4613
4614                    ctn.removeClass("h5Loading");
4615
4616                    log('stickyad start');
4617
4618                });
4619
4620                adsComponent.on(com.stickyadstv.vpaid.Ad.AD_CLICK_THRU, function(e) {
4621                    domElem.once.call( window, "focus", function(){
4622                        videoAd.skipBtn.end.call(_this, videoAd.stickyAds.complete.bind(_this));
4623                    });
4624                });
4625
4626                adsComponent.on(com.stickyadstv.AdsComponent.NOTIFY_ADS_COMPLETE, function(e) {});
4627
4628                adsComponent.on(com.stickyadstv.AdsComponent.REQUEST_PLAY, _this.play.bind(_this));
4629
4630                adsComponent.on(com.stickyadstv.AdsComponent.REQUEST_PAUSE, _this.pause.bind(_this));
4631
4632                adsComponent.on(com.stickyadstv.AdsComponent.AD_COMPLETE, videoAd.stickyAds.complete.bind(_this));
4633
4634                adsComponent.on(com.stickyadstv.AdsComponent.LOAD_FAILED, videoAd.stickyAds.complete.bind(_this));
4635
4636                adsComponent.on(com.stickyadstv.AdsComponent.AD_ERROR, videoAd.stickyAds.onError.bind(_this));
4637
4638                adsComponent.on(com.stickyadstv.AdsComponent.TIME_REMAINING_UPDATE, function(e) {
4639
4640                    duration = duration || e.detail.remaining;
4641
4642                    var curr = duration - e.detail.remaining;
4643
4644                    // _this.updateProgressBar({
4645                    //     curr : curr,
4646                    //     total : duration
4647                    // });
4648
4649                    videoAd.tracking.check.call( _this, {
4650                        duration : duration,
4651                        currentTime : curr
4652                    });
4653
4654                });
4655
4656                adsComponent.play(adContainer);
4657
4658                // mark , used in mobile ??
4659                // adContainer.on("click", _this.play.bind(_this));
4660
4661                videoAd.stickyAds.adContainer  = adContainer;
4662                videoAd.stickyAds.adsComponent = adsComponent;
4663
4664                if (_this.ended()) {
4665                    _this.play();
4666                    _this.adCompleteCallbacks.unshift(function(){
4667                        _this.pause();
4668                        setTimeout(function(){
4669                            _this.svg.playIcon.set.call(_this,"replay");
4670                            _this.playNext.init.call(_this);
4671                            _this.updateProgressBar({
4672                                curr : 1,
4673                                total : 1
4674                            })
4675                        },200);
4676                    });
4677
4678                }
4679
4680                videoAd.ready.call(_this);
4681                // video.once("seeked", function(evt){
4682                //     ctn.addClass("h5Loading")
4683                // }, true)
4684
4685            },
4686
4687            complete: function( error ) {
4688
4689                var ctn      = this.container,
4690                    stickyAd = this.videoAd.stickyAds;
4691
4692                clearInterval( this.skipCountDown );
4693
4694                removeAll( ctn.find(".h5AdPlayBtn") );
4695                // removeAll( document.querySelectorAll('body > .stickyads-overlay') );
4696
4697                stickyAd.adsComponent.dispose();
4698                stickyAd.adContainer.remove();
4699
4700                this.videoAd.complete.call(this);
4701
4702
4703            },
4704
4705            onError: function(event) {
4706
4707                var _this = this;
4708                var stickyAd = this.videoAd.stickyAds;
4709
4710                try {
4711                    stickyAd.adsComponent.dispose();
4712                    stickyAd.adContainer.remove();
4713                    _this.videoAd.backupAd.call(_this);
4714                } catch (error) {}
4715
4716                
4717
4718            }
4719
4720        },
4721
4722        googleAd: {
4723
4724            sdk : 'http://imasdk.googleapis.com/js/sdkloader/ima3.js',
4725
4726            init: function(url, config) {
4727                
4728                var _this       = this,
4729                    video       = this.video,
4730                    ctn         = this.container,
4731                    googleAd    = this.videoAd.googleAd,
4732                    refObj      = ctn.find(".h5PlayPauseLayer") || video,
4733                    adContainer = createElement("div", "h5GoogleAdCtn" ),
4734                    adDisplayContainer, adsLoader, adsRequest;
4735
4736                clearTimeout( this.adLoadingTimeOut );
4737
4738                googleAd.play = function() {
4739
4740                    try {
4741
4742                        clearTimeout(_this.googleAdStopAdTimeOut);
4743                        clearTimeout(_this.googleAdInitTimeOut);
4744                        window.removeEventListener("resize", googleAd.resize);
4745
4746                        googleAd.adsManager.init(video.clientWidth, video.clientHeight, google.ima.ViewMode.NORMAL);
4747
4748                        googleAd.adsManager.start();
4749
4750                        _this.googleAdStopAdTimeOut = setTimeout(function() {
4751                            log("stop googleAd timeout");
4752                            googleAd.complete.call(_this);
4753                        }, 5000);
4754                        
4755                        window.addEventListener("resize", googleAd.resize);
4756                        
4757                        if ( config.skip ){
4758                            _this.videoAd.skipBtn.create.call(_this, googleAd.complete.bind(_this));
4759                        }
4760                        
4761                    }
4762                    catch (adError) {
4763
4764                        console.log(adError);
4765
4766                        _this.googleAdInitTimeOut = setTimeout(googleAd.play, 1000);
4767
4768                    }
4769
4770                };
4771                googleAd.start = function() {
4772
4773                    if (googleAd.error) return;
4774
4775                    if ( _this.mobile ) {
4776                        _this.muted = true;
4777                    }
4778
4779                    _this.pause();
4780
4781                    ctn.addClass("h5PlayingAd");
4782                    // ctn.addClass("h5PlayingAd " + (config.hidetimeline?"h5HideTimeLine":""));
4783
4784                    googleAd.adDisplayContainer.initialize();
4785
4786                    googleAd.play();
4787
4788                };
4789                googleAd.resize = function(){
4790                    if (ctn.hasClass('h5FullScreen')) {
4791                        googleAd.adsManager.resize(screen.width, screen.height, google.ima.ViewMode.FULLSCREEN);
4792                    } else googleAd.adsManager.resize(video.clientWidth, video.clientHeight, google.ima.ViewMode.FULLSCREEN);
4793                }
4794
4795                refObj.after(adContainer);
4796
4797                google.ima.settings.setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.INSECURE);                
4798
4799                adDisplayContainer = new google.ima.AdDisplayContainer(adContainer, video);
4800
4801                log("googleAd init");
4802
4803                adsLoader = new google.ima.AdsLoader(adDisplayContainer);
4804
4805                adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.INSECURE);
4806
4807                adsLoader.addEventListener(
4808                    google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
4809                    googleAd.onAdsManagerLoaded.bind(_this),
4810                    false);
4811                adsLoader.addEventListener(
4812                    google.ima.AdErrorEvent.Type.AD_ERROR,
4813                    googleAd.onAdError.bind(_this),
4814                    false);
4815
4816                adsRequest = new google.ima.AdsRequest();
4817
4818                adsRequest.adTagUrl = url;
4819
4820                adsRequest.linearAdSlotWidth = video.clientWidth;
4821                adsRequest.linearAdSlotHeight = video.clientHeight;
4822                adsRequest.nonLinearAdSlotWidth = video.clientWidth;
4823                adsRequest.nonLinearAdSlotHeight = video.clientHeight;
4824
4825                adsLoader.requestAds(adsRequest);
4826
4827                googleAd.adsLoader = adsLoader;
4828                googleAd.adContainer = adContainer;
4829                googleAd.adDisplayContainer = adDisplayContainer;
4830
4831                if (_this.ended()) {
4832                    setTimeout(googleAd.start,1000);
4833                } else {
4834                    video.once("play", googleAd.start);
4835                }
4836
4837                googleAd.error = false;
4838
4839            },
4840
4841            onAdsManagerLoaded: function(adsManagerLoadedEvent) {
4842
4843                var googleAd  = this.videoAd.googleAd,
4844                    onAdError = googleAd.onAdError.bind(this),
4845                    onAdEvent = googleAd.onAdEvent.bind(this),
4846                    adsManager,
4847                    adsRenderingSettings = new google.ima.AdsRenderingSettings();
4848
4849                adsRenderingSettings.bitrate = 1000;
4850
4851                adsManager = adsManagerLoadedEvent.getAdsManager(this.video, adsRenderingSettings);
4852
4853                adsManager.addEventListener(
4854                    google.ima.AdErrorEvent.Type.AD_ERROR,
4855                    onAdError);
4856                adsManager.addEventListener(
4857                    google.ima.AdEvent.Type.ALL_ADS_COMPLETED,
4858                    onAdEvent);
4859                adsManager.addEventListener(
4860                    google.ima.AdEvent.Type.LOADED,
4861                    onAdEvent);
4862                adsManager.addEventListener(
4863                    google.ima.AdEvent.Type.STARTED,
4864                    onAdEvent);
4865                adsManager.addEventListener(
4866                    google.ima.AdEvent.Type.COMPLETE,
4867                    onAdEvent);
4868                adsManager.addEventListener(
4869                    google.ima.AdEvent.Type.SKIPPED,
4870                    onAdEvent);
4871                adsManager.addEventListener(
4872                    google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED,
4873                    onAdEvent);    
4874                adsManager.addEventListener(
4875                    google.ima.AdEvent.Type.CLICK,
4876                    onAdEvent);    
4877
4878                googleAd.adsManager = adsManager;
4879
4880                this.videoAd.ready.call(this);
4881
4882            },
4883
4884            onAdEvent: function(adEvent) {
4885
4886                var ad          = adEvent.getAd(),
4887                    _this       = this,
4888                    videoAd     = this.videoAd,
4889                    video       = this.video,
4890                    ctn         = this.container,
4891                    googleAd    = videoAd.googleAd,
4892                    // progressBar = ctn.find(".h5ProgressBar"),
4893                    duration    = 0;
4894
4895                switch (adEvent.type) {
4896
4897                    // case google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED:
4898
4899                    //     console.log( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED );
4900
4901                    //     break;
4902                    case google.ima.AdEvent.Type.CLICK:
4903                        videoAd.tracking.load.call(_this, "clickTracking");
4904
4905                        var videoTag = ctn.find(".h5GoogleAdCtn video");
4906                        videoTag && window.addEventListener("focus", function focus() {
4907                            window.removeEventListener("focus", focus);
4908                            googleAd.adsManager.resume();
4909                        })
4910
4911                        break;
4912                    case google.ima.AdEvent.Type.VOLUME_MUTED:
4913
4914                        console.log( google.ima.AdEvent.Type.VOLUME_MUTED );
4915
4916                        break;
4917                    case google.ima.AdEvent.Type.VOLUME_CHANGED:
4918
4919                        console.log( google.ima.AdEvent.Type.VOLUME_CHANGED );
4920
4921                        break;
4922
4923                    case google.ima.AdEvent.Type.LOADED:
4924
4925                        if (!ad.isLinear()) {
4926                            _this.play();
4927                        }
4928
4929                        googleAd.resize();
4930
4931                        googleAd.adsManager.setVolume( _this.muted ? 0 : _this.volume);
4932
4933                        // ctn.addClass('h5Loading');
4934
4935                        clearTimeout(_this.googleAdStopAdTimeOut);
4936
4937                        break;
4938
4939                    case google.ima.AdEvent.Type.STARTED:
4940
4941                        if (ad.isLinear() && _this.h5playerAvailable) {
4942
4943                            _this.pause();
4944
4945                            ctn.removeClass("h5Loading");
4946                            clearInterval(_this.googleAdIntervalTimer);
4947                            _this.googleAdIntervalTimer = setInterval(function() {
4948
4949                                if (_this.adCompleted) {
4950                                    clearInterval(_this.googleAdIntervalTimer);
4951                                    return false;
4952                                }
4953                                
4954                                var remainingTime = Math.max(0, googleAd.adsManager.getRemainingTime());
4955
4956                                duration = duration || remainingTime;
4957
4958                                // if (duration === remainingTime) {
4959                                //     ctn.addClass("h5HideTimeLine");
4960                                // }
4961
4962                                // _this.updateProgressBar({
4963                                //     curr : duration - remainingTime,
4964                                //     total : duration
4965                                // })
4966
4967                                videoAd.tracking.check.call( _this, {
4968                                    duration : duration,
4969                                    currentTime : duration - remainingTime
4970                                });
4971
4972                            }, 300);
4973
4974                            googleAd.adsManager.resume();
4975
4976                        }
4977
4978                        break;
4979
4980                    case google.ima.AdEvent.Type.ALL_ADS_COMPLETED:
4981
4982                        clearInterval(_this.googleAdIntervalTimer);
4983
4984                        googleAd.complete.call(_this);
4985                        videoAd.tracking.load.call(_this, "complete");
4986
4987                        break;
4988
4989                    case google.ima.AdEvent.Type.SKIPPED:
4990
4991                        googleAd.complete.call(_this);
4992
4993                        break;
4994
4995                }
4996
4997
4998            },
4999
5000            destroy : function(){
5001
5002                var googleAd = this.videoAd.googleAd;
5003
5004                try{
5005                    googleAd.adsManager.destroy();
5006                    googleAd.adsLoader.destroy();
5007                    // googleAd.adsLoader.contentComplete();
5008                }catch(error){
5009                    log("GoogleAd Error:" + error);
5010                }
5011
5012                clearTimeout(this.googleAdStopAdTimeOut);
5013                clearTimeout(this.googleAdInitTimeOut);
5014                clearInterval(this.googleAdIntervalTimer);
5015
5016                removeAll( this.container.find(".h5GoogleAdCtn") );
5017
5018            },
5019
5020            onAdError: function(adErrorEvent) {
5021
5022                console.log(adErrorEvent.getError());
5023
5024                this.videoAd.googleAd.error = true;
5025
5026                this.videoAd.googleAd.destroy.call(this);
5027                this.videoAd.backupAd.call(this);
5028
5029            },
5030
5031            complete: function() {
5032
5033                window.removeEventListener("resize", this.videoAd.googleAd.resize);
5034
5035                this.videoAd.googleAd.destroy.call(this);
5036                this.videoAd.complete.call(this);
5037
5038            }
5039
5040        }
5041
5042    };
5043
5044    h5Player.fn = h5Player.prototype.fn = {
5045
5046        platform: function() {
5047
5048            var ua          = navigator.userAgent,
5049                width       = 768,
5050                screenWidth = (screen.width < width) || (window.matchMedia && window.matchMedia('only screen and (max-width: ' + width + 'px)').matches),
5051                iOS         = ua.match(/iPhone|iPad|iPod/i) ? true : false,
5052                mobile      = /mobi/i.test(ua) && screenWidth ? true : false,
5053                iPhone      = iOS && screen.width < 768;
5054
5055            var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection || {};
5056            var wifi = this.wifi = /wifi/i.test(connection.type);
5057
5058            return {
5059                iOS : iOS,
5060                mobile : mobile,
5061                iPhone : iPhone,
5062                CriOS  : /CriOS/i.test(ua) && iPhone, //chrome on iphone
5063                touchable : 'ontouchstart' in window || navigator.msMaxTouchPoints,
5064                IE9 : document.documentMode === 9,
5065                wifi: wifi,
5066                cssSupport : {
5067                    objectfit : "object-fit" in window.getComputedStyle(document.body),
5068                }
5069            };
5070
5071        },
5072
5073        setCookie: function(cname, cvalue, exdays, path) {
5074
5075            path = path || "/";
5076            exdays = exdays || 365;
5077
5078            var d = new Date();
5079            d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
5080            var expires = "expires=" + d.toUTCString();
5081            document.cookie = cname + "=" + cvalue + "; " + expires + ";path=" + path;
5082
5083        },
5084
5085        getCookie: function(cname) {
5086
5087            var name = cname + "=";
5088            var ca   = document.cookie.split(';');
5089            for (var i = ca.length-1; i >= 0; i--) {
5090                var c = ca[i];
5091                while (c.charAt(0) == ' ') {
5092                    c = c.substring(1);
5093                }
5094                if (c.indexOf(name) === 0) {
5095                    return c.substring(name.length, c.length);
5096                }
5097            }
5098            return "";
5099
5100        },
5101
5102        ajax : function(options){
5103
5104            options          = options || {};
5105            options.type     = (options.type || "GET").toUpperCase();
5106            options.dataType = options.dataType.toLowerCase() || "text";
5107            options.async    = options.async === undefined ? true : options.async;
5108            options.success  = options.success || noop;
5109            options.fail     = options.fail || noop;
5110
5111            var params = formatParams(options.data);
5112            var xhr;
5113
5114            if (!!window.XMLHttpRequest) {
5115                xhr = new XMLHttpRequest();
5116            }else {
5117                xhr = new XDomainRequest();
5118            }
5119
5120            if ( !options.url ) {
5121                options.fail(xhr.status, xhr.statusText);
5122                return;
5123            }
5124
5125            xhr.onreadystatechange = function (e) {
5126               if (xhr.readyState == 4) {
5127                   var status = xhr.status;
5128                   if (status >= 200 && status < 300) {
5129                        options.success( parse(xhr.responseText), xhr.responseXML);
5130                   } else {
5131                        options.fail(xhr.status, xhr.statusText);
5132                   }
5133               }
5134            };
5135
5136            if (options.type == "GET") {
5137               xhr.open("GET", options.url, options.async);
5138               xhr.send(null);
5139            } else if (options.type == "POST") {
5140               xhr.open("POST", options.url, options.async);
5141               xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
5142               xhr.send(params);
5143            }
5144
5145            function parse(str){
5146
5147                if( options.dataType === "json" ){
5148                    return JSON.parse(str);
5149                }
5150                else if( options.dataType === "xml" ){
5151                    return h5Player.fn.parseXML(str);
5152                }
5153
5154                return str;
5155
5156            }
5157
5158            function formatParams(data) {
5159               var arr = [];
5160               for (var name in data) {
5161                   arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name]));
5162               }
5163               arr.push(("v=" + Math.random()).replace(".",""));
5164               return arr.join("&");
5165            }
5166
5167
5168        },
5169
5170        loadXML: function(input, success, fail, _async) {
5171
5172            var url      = input,
5173                storage  = h5Player.prototype.storage,
5174                id,time;
5175
5176            fail    = fail || noop;
5177            success = success || noop;
5178
5179            function shortDelay(callback, result) {
5180                setTimeout(function(){
5181                    callback(result);
5182                }, 0);
5183            }
5184
5185            function store( condition, type, key, value ){
5186
5187                if ( condition ) {
5188                    if (storage[type].length === undefined) {
5189                        storage[type].length = 0;
5190                    }
5191                    storage[type][key] = value;
5192                    storage[type].length++;
5193                }
5194                
5195            }
5196
5197            function extract( condition, type, key ){
5198
5199                if( condition && storage[type][key] ){
5200
5201                    if( typeof storage[type][key] === "object" ){
5202                        shortDelay(success, storage[type][key]);
5203                        return true;
5204                    }else{
5205                        shortDelay(fail, storage[type][key]);
5206                        return false;
5207                    }
5208
5209                }
5210
5211            }
5212
5213            if( typeof input === "object" ){
5214
5215                id   = input.videoId || input[1];
5216                time = input.createTime || input[0];
5217
5218                if( storage.videos[id] ){
5219                    shortDelay(success, storage.videos[id] );
5220                    return;
5221                }
5222
5223                url = 'http://datafeed.on.cc/ontv/xml/Metadata/Video/' + h5Player.fn.dateFormat(new Date( time * 1000), 'yyyymm') + '/' + id + '.xml';
5224
5225            }
5226
5227            var groupXML    = url.indexOf("/xml/Group/") !== -1,
5228                keywordXML  = url.indexOf("/xml/Keyword/") !== -1,
5229                mostViewXML = url.indexOf("/xml/Ranking/") !== -1,
5230                videoXML    = url.indexOf('/Metadata/Video/') !== -1,
5231                value       = url.split("/").slice(-1)[0].split(".")[0];
5232            
5233            if( extract(videoXML, "videos", value) || 
5234                extract(groupXML, "groups", value) ||
5235                extract(keywordXML, "keywords", value) ||
5236                extract(mostViewXML, "mostview", value) ){
5237                return;
5238            }
5239
5240            if (url.indexOf('.js') !== -1) {
5241                return;
5242            }
5243
5244            h5Player.fn.ajax({
5245                url : url,
5246                dataType : "xml",
5247                async : _async,
5248                success : function( xml ){
5249                    store( videoXML, "videos", value, xml );
5250                    store( keywordXML, "keywords", value, xml);
5251                    store( groupXML, "groups", value, xml);
5252                    store( mostViewXML, "mostview", value, xml);
5253                    success( xml );
5254                },
5255                fail : function( status , statusText ){
5256                    store( keywordXML, "keywords", value, status);
5257                    store( groupXML, "groups", value, status);
5258                    store( mostViewXML, "mostview", value, status);
5259                    fail( status, statusText );
5260                }
5261            });
5262
5263        },
5264
5265        loadRecentYearsList : function( type, value, callback, config ){
5266
5267            config = config || {};
5268
5269            var year    = config.year || new Date().getFullYear(),
5270                max     = config.max || 3,
5271                arr     = [],
5272                result  = [],
5273                counter = 0;
5274
5275            function check(){
5276
5277                counter++;
5278
5279                if (counter >= max) {
5280
5281                    arr.forEach(function(_arr){
5282                        // _arr 有機會 undefined
5283                        result = result.concat(_arr || []);
5284                    });
5285
5286                    callback(result);
5287
5288                }
5289
5290            }
5291
5292            function success (xml) {
5293
5294                var index = this;
5295
5296                arr[index] = Array.prototype.slice.call(xml.getElementsByTagName("video"));
5297
5298                check();
5299
5300            }
5301
5302            for (var i = 0; i < max; i++) {
5303                var _year = year - i;
5304                h5Player.fn.loadXML(
5305                    'http://datafeed.on.cc/ontv/xml/'+ type +'/' + _year + '/' + value + '_' + _year + '.xml',
5306                    success.bind(i),
5307                    check,
5308                    config.async);
5309            }
5310
5311        },
5312
5313        loadXMLByKeyWord: function(keyword, callback, conifg) {
5314
5315           h5Player.fn.loadRecentYearsList("Keyword", keyword, callback, conifg);
5316
5317        },
5318
5319        loadXMLByGroup: function(group, callback, conifg) {
5320
5321           h5Player.fn.loadRecentYearsList("Group", group, callback, conifg);
5322
5323        },
5324
5325        loadVideoListCallBack: function(obj, config, callback) {
5326
5327            extend( config, this.commonConfig );
5328
5329            var list                = [],
5330                videos              = obj.querySelectorAll ? obj.querySelectorAll("video") : obj,
5331                limit               = Math.min( config.videoListCallBackLimit || 10000 , videos.length ) - 1,
5332                startIndex          = Math.min(limit, config.startIndex || 0),
5333                xmlLoaded           = config.xmlLoaded ? config.xmlLoaded : noop,
5334                noOfVideosXmlLoaded = 0;
5335
5336            delete config.xmlLoaded;
5337
5338            var parentPlayer = config.parentPlayer || new h5Player(config);
5339
5340            each(videos, function(val, count) {
5341				
5342                if (count <= limit) {
5343
5344                    config.preload      = false;
5345                    config.videoId      = val[1] || val.videoId || val.textContent;
5346                    config.createTime   = val[0] || val.createTime || val.getAttribute("createTime");
5347                    config.parentPlayer = parentPlayer;
5348                    config.xmlLoaded    = function() {
5349                        
5350                        xmlLoaded.call(this);
5351                        
5352                        if (noOfVideosXmlLoaded == limit) {
5353
5354                            if( config.disablePlayNext !== true && list.length > 1 ){
5355
5356                                parentPlayer.videoList       = parentPlayer.videoList || [];
5357                                parentPlayer.videoList       = parentPlayer.videoList.concat( list );
5358                                parentPlayer.disablePlayNext = false;
5359
5360                                if ( parentPlayer.videoListIndex === undefined ) {
5361                                    parentPlayer.videoListIndex = startIndex;
5362                                }
5363                                
5364                            }
5365
5366                            if( !parentPlayer.video.src ){
5367                                
5368                                parentPlayer.preload = true;
5369                                parentPlayer.setVideoSrc(list[startIndex], function(){
5370                                    // callback
5371                                })
5372
5373                                // list[startIndex].switch({
5374                                //     autoplay: config.autoplay || false
5375                                // });
5376                
5377
5378                            } 
5379
5380                            callback.call( parentPlayer , list );
5381
5382                        }
5383
5384                        noOfVideosXmlLoaded++;
5385
5386                    };
5387                    
5388                    delete config.container;
5389
5390                    list.push(new h5Player(config));
5391					
5392                }
5393
5394            });
5395
5396
5397        },
5398
5399        loadScript: function(url, success, fail) {
5400
5401            if ( scriptLoadStarted.indexOf(url) === -1 ) {
5402
5403                scriptLoadStarted.push(url);
5404
5405                var script = document.createElement("script");
5406
5407                script.setAttribute('type', 'text/javascript');
5408                script.setAttribute('src', url);
5409                script.onload  = success || noop;
5410                script.onerror = fail || noop;
5411
5412                document.body.appendChild(script);
5413                
5414            }
5415
5416        },
5417
5418        parseXML: function(xmlStr) {
5419
5420            if (window.DOMParser) {
5421                return (new window.DOMParser()).parseFromString(xmlStr, "text/xml");
5422            }
5423            else if (typeof window.ActiveXObject != "undefined" && new window.ActiveXObject("Microsoft.XMLDOM")) {
5424                var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
5425                    xmlDoc.async = "false";
5426                    xmlDoc.loadXML(xmlStr);
5427
5428                return xmlDoc;
5429            }
5430            else {
5431                return null;
5432            }
5433
5434        },
5435
5436        dateFormat: function(dateObj, pattern) {
5437            // Some common format strings
5438            var masks = {
5439                'default': 'ddd mmm dd yyyy HH:MM:ss'
5440            };
5441            // Internationalization strings
5442            var i18n = {
5443                dayNames: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', '日', '一', '二', '三', '四', '五', '六'],
5444                monthNames: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
5445            };
5446
5447            var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
5448                timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
5449                timezoneClip = /[^-+\dA-Z]/g,
5450                pad = function(val, len) {
5451                    len = len || 2;
5452                    return h5Player.fn.digitPad('0',val,len);
5453                };
5454
5455            var formatter = function(date, mask, utc) {
5456
5457                mask = String(masks[mask] || mask || masks['default']);
5458
5459                // Allow setting the utc argument via the mask
5460                if (mask.slice(0, 4) == 'UTC:') {
5461                    mask = mask.slice(4);
5462                    utc = true;
5463                }
5464
5465                var _ = utc ? 'getUTC' : 'get',
5466                    d = date[_ + 'Date'](),
5467                    D = date[_ + 'Day'](),
5468                    m = date[_ + 'Month'](),
5469                    y = date[_ + 'FullYear'](),
5470                    H = date[_ + 'Hours'](),
5471                    M = date[_ + 'Minutes'](),
5472                    s = date[_ + 'Seconds'](),
5473                    L = date[_ + 'Milliseconds'](),
5474                    o = utc ? 0 : date.getTimezoneOffset(),
5475                    flags = {
5476                        d: d,
5477                        dd: pad(d),
5478                        ddd: i18n.dayNames[D],
5479                        dddd: i18n.dayNames[D + 7],
5480                        m: m + 1,
5481                        mm: pad(m + 1),
5482                        mmm: i18n.monthNames[m],
5483                        mmmm: i18n.monthNames[m + 12],
5484                        yy: y.toString().slice(2),
5485                        yyyy: y,
5486                        h: H % 12 || 12,
5487                        hh: pad(H % 12 || 12),
5488                        H: H,
5489                        HH: pad(H),
5490                        M: M,
5491                        MM: pad(M),
5492                        s: s,
5493                        ss: pad(s),
5494                        l: pad(L, 3),
5495                        L: pad(L > 99 ? Math.round(L / 10) : L),
5496                        t: H < 12 ? "a" : "p",
5497                        tt: H < 12 ? "am" : "pm",
5498                        T: H < 12 ? "A" : "P",
5499                        TT: H < 12 ? "AM" : "PM"
5500                    };
5501
5502                return mask.replace(token, function($0) {
5503                    return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
5504                });
5505            };
5506
5507            if (typeof dateObj === 'string') {
5508                dateObj = h5Player.fn.strToDate(dateObj);
5509            }
5510
5511            return formatter(dateObj, pattern, false);
5512
5513        },
5514
5515        digitPad : function(symbol, val, len) {
5516            var str = String(val);
5517            while (str.length < len) { str= symbol+str; }
5518            return str;
5519        },
5520
5521        strToDate : function(str) {
5522            if (str.length >= 8) {
5523                var yyyy = str.substring(0,4);
5524                var mm = parseInt(str.substring(4,6), 10) - 1;
5525                var dd = str.substring(6,8);
5526                var HH = (str.length >= 10) ? str.substring(8,10) : 0;
5527                var MM = (str.length >= 12) ? str.substring(10,12) : 0;
5528                var ss = (str.length >= 14) ? str.substring(12,14) : 0;
5529                return new Date(yyyy, mm, dd, HH, MM, ss);
5530            }
5531            return new Date();
5532        },
5533
5534    };
5535
5536    window.h5Player = h5Player;
5537    window.h5DefaultConfig = h5DefaultConfig;
5538    
5539
5540}());

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.