alivideo.js 123 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336
  1. (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2. /**
  3. * flash的应用信息
  4. */
  5. module.exports = {
  6. //domain: 'g-assets.daily.taobao.net',
  7. domain: 'g.alicdn.com',
  8. flashVersion: '1.2.1',
  9. h5Version: '1.4.7',
  10. logReportTo: '//videocloud.cn-hangzhou.log.aliyuncs.com/logstores/player/track'
  11. };
  12. },{}],2:[function(require,module,exports){
  13. /**
  14. * @fileoverview prismplayer的入口模块
  15. */
  16. var Player = require('./player/player');
  17. var FlashPlayer = require('./player/flashplayer');
  18. var Dom = require('./lib/dom');
  19. var UA = require('./lib/ua');
  20. var _ = require('./lib/object');
  21. var cfg = require('./config');
  22. var prism = function (opt) {
  23. var id = opt.id,
  24. tag;
  25. //如果是一个字符串,我们就认为是元素的id
  26. if('string' === typeof id){
  27. // id为#string的情况
  28. if (id.indexOf('#') === 0) {
  29. id = id.slice(1);
  30. }
  31. // 如果在此id上创建过prismplayer实例,返回该实例
  32. if (prism.players[id]) {
  33. return prism.players[id];
  34. } else {
  35. tag = Dom.el(id);
  36. }
  37. } else {
  38. //否则就认为是dom 元素
  39. tag = id;
  40. }
  41. if(!tag || !tag.nodeName){
  42. throw new TypeError('没有为播放器指定容器');
  43. }
  44. var option = _.merge(_.copy(prism.defaultOpt), opt);
  45. //isLive 判断
  46. if (UA.IS_MOBILE&&opt.isLive) {
  47. option.skinLayout=[
  48. {name:"bigPlayButton", align:"blabs", x:30, y:80},
  49. {
  50. name:"controlBar", align:"blabs", x:0, y:0,
  51. children: [
  52. {name:"liveDisplay", align:"tlabs", x: 15, y:25},
  53. {name:"fullScreenButton", align:"tr", x:20, y:25},
  54. {name:"volume", align:"tr", x:20, y:25}
  55. ]
  56. }
  57. ]
  58. };
  59. if (UA.IS_IOS) {
  60. for(var i=0;i<option.skinLayout.length;i++){
  61. if(option.skinLayout[i].name=="controlBar"){
  62. var children=option.skinLayout[i];
  63. for(var c=0;c<children.children.length;c++){
  64. if(children.children[c].name=="volume"){
  65. children.children.splice(c,1);
  66. break;
  67. }
  68. }
  69. }
  70. }
  71. };
  72. if (option.width) {
  73. tag.style.width = option.width;
  74. }
  75. if (option.height) {
  76. var per_idx = option.height.indexOf("%");
  77. if (per_idx > 0)
  78. {
  79. var screen_height = window.screen.height;
  80. var per_value = option.height.replace("%", "");
  81. if(!isNaN(per_value))
  82. {
  83. var scale_value = screen_height * 9 * parseInt(per_value) / 1000;
  84. tag.style.height = String(scale_value % 2 ? scale_value + 1: scale_value) + "px";
  85. }
  86. else
  87. {
  88. tag.style.height = option.height;
  89. }
  90. }
  91. else
  92. {
  93. tag.style.height = option.height;
  94. }
  95. }
  96. //如果tag已指向一个存在的player,则返回这个player实例
  97. //否则初始化播放器
  98. return tag['player'] ||
  99. (UA.IS_MOBILE ? new Player(tag, option) : new FlashPlayer(tag, option));
  100. //new Player(tag, option);
  101. }
  102. var prismplayer = window['prismplayer'] = prism;
  103. //全局变量,记录所有的播放器
  104. prism.players = {};
  105. /**
  106. * 默认的配置项
  107. */
  108. prism.defaultOpt = {
  109. preload: false, // 是否预加载
  110. autoplay: true, // 是否自动播放
  111. useNativeControls: false, // 是否使用默认的控制面板
  112. width: '100%', // 播放器宽度
  113. height: '300px', // 播放器高度
  114. cover: '', // 默认封面图
  115. from: 'prism_aliyun', // 渠道来源
  116. trackLog: true, // 是否需要打点
  117. waterMark:"", // swf水印配置 http://taobao.com/wm.swf||BR||11123 以||分割url||对齐方式||参数
  118. isLive:false, //是否为直播状态(直播暂时只有flash版本支持)
  119. /* vid 淘宝视频的视频id,必填 */ // 视频id
  120. skinRes: '//' + cfg.domain + '/de/prismplayer-flash/' + cfg.flashVersion + '/atlas/defaultSkin', // String, ui皮肤图片地址,非必填,不填使用默认,纯h5播放器可以不考虑这个字段
  121. skinLayout: [ // false | Array, 播放器使用的ui组件,非必填,不传使用默认,传false或[]整体隐藏
  122. {name:"bigPlayButton", align:"blabs", x:30, y:80},
  123. {
  124. name:"controlBar", align:"blabs", x:0, y:0,
  125. children: [
  126. {name:"progress", align:"tlabs", x: 0, y:0},
  127. {name:"playButton", align:"tl", x:15, y:26},
  128. {name:"nextButton", align:"tl", x:10, y:26},
  129. {name:"timeDisplay", align:"tl", x:10, y:24},
  130. {name:"fullScreenButton", align:"tr", x:10, y:25},
  131. //{name:"setButton", align:"tr", x:0, y:25},
  132. {name:"streamButton", align:"tr", x:10, y:23},
  133. {name:"volume", align:"tr", x:10, y:25}
  134. ]
  135. },
  136. {
  137. name:"fullControlBar", align:"tlabs", x:0, y:0,
  138. children: [
  139. {name:"fullTitle", align:"tl", x:25, y:6},
  140. {name:"fullNormalScreenButton", align:"tr", x:24, y:13},
  141. {name:"fullTimeDisplay", align:"tr", x:10, y:12},
  142. {name:"fullZoom", align:"cc"}
  143. ]
  144. }
  145. ]
  146. }
  147. // AMD
  148. if (typeof define === 'function' && define['amd']) {
  149. define([], function(){ return prismplayer; });
  150. // commonjs, 支持browserify
  151. } else if (typeof exports === 'object' && typeof module === 'object') {
  152. module['exports'] = prismplayer;
  153. }
  154. },{"./config":1,"./lib/dom":5,"./lib/object":10,"./lib/ua":12,"./player/flashplayer":16,"./player/player":17}],3:[function(require,module,exports){
  155. module.exports.get = function(cname) {
  156. var name = cname + '';
  157. var ca = document.cookie.split(';');
  158. for(var i = 0; i < ca.length; i++) {
  159. var c = ca[i].trim();
  160. if(c.indexOf(name) == 0) {
  161. return unescape(c.substring(name.length + 1,c.length));
  162. }
  163. }
  164. return '';
  165. };
  166. module.exports.set = function(cname, cvalue, exdays) {
  167. var d = new Date();
  168. d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
  169. var expires = 'expires=' + d.toGMTString();
  170. document.cookie = cname + '=' + escape(cvalue) + '; ' + expires;
  171. };
  172. },{}],4:[function(require,module,exports){
  173. var _ = require('./object');
  174. /**
  175. * Element Data Store. Allows for binding data to an element without putting it directly on the element.
  176. * Ex. Event listneres are stored here.
  177. * (also from jsninja.com, slightly modified and updated for closure compiler)
  178. * @type {Object}
  179. * @private
  180. */
  181. module.exports.cache = {};
  182. /**
  183. * Unique ID for an element or function
  184. * @type {Number}
  185. * @private
  186. */
  187. module.exports.guid = function(len, radix) {
  188. var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
  189. var uuid = [], i;
  190. radix = radix || chars.length;
  191. if (len) {
  192. for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
  193. } else {
  194. var r;
  195. uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
  196. uuid[14] = '4';
  197. for (i = 0; i < 36; i++) {
  198. if (!uuid[i]) {
  199. r = 0 | Math.random()*16;
  200. uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
  201. }
  202. }
  203. }
  204. return uuid.join('');
  205. };
  206. /**
  207. * Unique attribute name to store an element's guid in
  208. * @type {String}
  209. * @constant
  210. * @private
  211. */
  212. module.exports.expando = 'vdata' + (new Date()).getTime();
  213. /**
  214. * Returns the cache object where data for an element is stored
  215. * @param {Element} el Element to store data for.
  216. * @return {Object}
  217. * @private
  218. */
  219. module.exports.getData = function(el){
  220. var id = el[module.exports.expando];
  221. if (!id) {
  222. id = el[module.exports.expando] = module.exports.guid();
  223. module.exports.cache[id] = {};
  224. }
  225. return module.exports.cache[id];
  226. };
  227. /**
  228. * Returns the cache object where data for an element is stored
  229. * @param {Element} el Element to store data for.
  230. * @return {Object}
  231. * @private
  232. */
  233. module.exports.hasData = function(el){
  234. var id = el[module.exports.expando];
  235. return !(!id || _.isEmpty(module.exports.cache[id]));
  236. };
  237. /**
  238. * Delete data for the element from the cache and the guid attr from getElementById
  239. * @param {Element} el Remove data for an element
  240. * @private
  241. */
  242. module.exports.removeData = function(el){
  243. var id = el[module.exports.expando];
  244. if (!id) { return; }
  245. // Remove all stored data
  246. // Changed to = null
  247. // http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
  248. // module.exports.cache[id] = null;
  249. delete module.exports.cache[id];
  250. // Remove the expando property from the DOM node
  251. try {
  252. delete el[module.exports.expando];
  253. } catch(e) {
  254. if (el.removeAttribute) {
  255. el.removeAttribute(module.exports.expando);
  256. } else {
  257. // IE doesn't appear to support removeAttribute on the document element
  258. el[module.exports.expando] = null;
  259. }
  260. }
  261. };
  262. },{"./object":10}],5:[function(require,module,exports){
  263. /**
  264. * @fileoverview 封装对dom元素的基本操作
  265. */
  266. var _ = require('./object');
  267. /**
  268. * 根据id获取dom
  269. */
  270. module.exports.el = function(id){
  271. return document.getElementById(id);
  272. }
  273. /**
  274. * Creates an element and applies properties.
  275. * @param {String=} tagName Name of tag to be created.
  276. * @param {Object=} properties Element properties to be applied.
  277. * @return {Element}
  278. * @private
  279. */
  280. module.exports.createEl = function(tagName, properties){
  281. var el;
  282. tagName = tagName || 'div';
  283. properties = properties || {};
  284. el = document.createElement(tagName);
  285. _.each(properties, function(propName, val){
  286. // Not remembering why we were checking for dash
  287. // but using setAttribute means you have to use getAttribute
  288. // The check for dash checks for the aria-* attributes, like aria-label, aria-valuemin.
  289. // The additional check for "role" is because the default method for adding attributes does not
  290. // add the attribute "role". My guess is because it's not a valid attribute in some namespaces, although
  291. // browsers handle the attribute just fine. The W3C allows for aria-* attributes to be used in pre-HTML5 docs.
  292. // http://www.w3.org/TR/wai-aria-primer/#ariahtml. Using setAttribute gets around this problem.
  293. if (propName.indexOf('aria-') !== -1 || propName == 'role') {
  294. el.setAttribute(propName, val);
  295. } else {
  296. el[propName] = val;
  297. }
  298. });
  299. return el;
  300. };
  301. /**
  302. * Add a CSS class name to an element
  303. * @param {Element} element Element to add class name to
  304. * @param {String} classToAdd Classname to add
  305. * @private
  306. */
  307. module.exports.addClass = function(element, classToAdd){
  308. if ((' '+element.className+' ').indexOf(' '+classToAdd+' ') == -1) {
  309. element.className = element.className === '' ? classToAdd : element.className + ' ' + classToAdd;
  310. }
  311. };
  312. /**
  313. * Remove a CSS class name from an element
  314. * @param {Element} element Element to remove from class name
  315. * @param {String} classToAdd Classname to remove
  316. * @private
  317. */
  318. module.exports.removeClass = function(element, classToRemove){
  319. var classNames, i;
  320. if (element.className.indexOf(classToRemove) == -1) { return; }
  321. classNames = element.className.split(' ');
  322. // no arr.indexOf in ie8, and we don't want to add a big shim
  323. for (i = classNames.length - 1; i >= 0; i--) {
  324. if (classNames[i] === classToRemove) {
  325. classNames.splice(i,1);
  326. }
  327. }
  328. element.className = classNames.join(' ');
  329. };
  330. /**
  331. *
  332. */
  333. module.exports.getElementAttributes = function(tag){
  334. var obj, knownBooleans, attrs, attrName, attrVal;
  335. obj = {};
  336. // known boolean attributes
  337. // we can check for matching boolean properties, but older browsers
  338. // won't know about HTML5 boolean attributes that we still read from
  339. knownBooleans = ','+'autoplay,controls,loop,muted,default'+',';
  340. if (tag && tag.attributes && tag.attributes.length > 0) {
  341. attrs = tag.attributes;
  342. for (var i = attrs.length - 1; i >= 0; i--) {
  343. attrName = attrs[i].name;
  344. attrVal = attrs[i].value;
  345. // check for known booleans
  346. // the matching element property will return a value for typeof
  347. if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(','+attrName+',') !== -1) {
  348. // the value of an included boolean attribute is typically an empty
  349. // string ('') which would equal false if we just check for a false value.
  350. // we also don't want support bad code like autoplay='false'
  351. attrVal = (attrVal !== null) ? true : false;
  352. }
  353. obj[attrName] = attrVal;
  354. }
  355. }
  356. return obj;
  357. };
  358. /*
  359. */
  360. module.exports.insertFirst = function(child, parent){
  361. if (parent.firstChild) {
  362. parent.insertBefore(child, parent.firstChild);
  363. } else {
  364. parent.appendChild(child);
  365. }
  366. };
  367. // Attempt to block the ability to select text while dragging controls
  368. module.exports.blockTextSelection = function(){
  369. document.body.focus();
  370. document.onselectstart = function () { return false; };
  371. };
  372. // Turn off text selection blocking
  373. module.exports.unblockTextSelection = function(){ document.onselectstart = function () { return true; }; };
  374. /**
  375. * 设置或获取css属性
  376. */
  377. module.exports.css = function(el, cssName, cssVal) {
  378. if (!el.style) return false;
  379. if (cssName && cssVal) {
  380. el.style[cssName] = cssVal;
  381. return true;
  382. } else if (!cssVal && typeof cssName === 'string') {
  383. return el.style[cssName];
  384. } else if (!cssVal && typeof cssName === 'object') {
  385. _.each(cssName, function(k, v) {
  386. el.style[k] = v;
  387. });
  388. return true;
  389. }
  390. return false;
  391. };
  392. },{"./object":10}],6:[function(require,module,exports){
  393. var _ = require('./object');
  394. var Data = require('./data');
  395. /**
  396. * @fileoverview Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/)
  397. * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible)
  398. * This should work very similarly to jQuery's events, however it's based off the book version which isn't as
  399. * robust as jquery's, so there's probably some differences.
  400. */
  401. /**
  402. * Add an event listener to element
  403. * It stores the handler function in a separate cache object
  404. * and adds a generic handler to the element's event,
  405. * along with a unique id (guid) to the element.
  406. * @param {Element|Object} elem Element or object to bind listeners to
  407. * @param {String|Array} type Type of event to bind to.
  408. * @param {Function} fn Event listener.
  409. * @private
  410. */
  411. module.exports.on = function(elem, type, fn){
  412. if (_.isArray(type)) {
  413. return _handleMultipleEvents(module.exports.on, elem, type, fn);
  414. }
  415. var data = Data.getData(elem);
  416. // We need a place to store all our handler data
  417. if (!data.handlers) data.handlers = {};
  418. if (!data.handlers[type]) data.handlers[type] = [];
  419. if (!fn.guid) fn.guid = Data.guid();
  420. data.handlers[type].push(fn);
  421. if (!data.dispatcher) {
  422. data.disabled = false;
  423. data.dispatcher = function (event){
  424. if (data.disabled) return;
  425. event = module.exports.fixEvent(event);
  426. var handlers = data.handlers[event.type];
  427. if (handlers) {
  428. // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off.
  429. var handlersCopy = handlers.slice(0);
  430. for (var m = 0, n = handlersCopy.length; m < n; m++) {
  431. if (event.isImmediatePropagationStopped()) {
  432. break;
  433. } else {
  434. handlersCopy[m].call(elem, event);
  435. }
  436. }
  437. }
  438. };
  439. }
  440. if (data.handlers[type].length == 1) {
  441. if (elem.addEventListener) {
  442. elem.addEventListener(type, data.dispatcher, false);
  443. } else if (elem.attachEvent) {
  444. elem.attachEvent('on' + type, data.dispatcher);
  445. }
  446. }
  447. };
  448. /**
  449. * Removes event listeners from an element
  450. * @param {Element|Object} elem Object to remove listeners from
  451. * @param {String|Array=} type Type of listener to remove. Don't include to remove all events from element.
  452. * @param {Function} fn Specific listener to remove. Don't incldue to remove listeners for an event type.
  453. * @private
  454. */
  455. module.exports.off = function(elem, type, fn) {
  456. // Don't want to add a cache object through getData if not needed
  457. if (!Data.hasData(elem)) return;
  458. var data = Data.getData(elem);
  459. // If no events exist, nothing to unbind
  460. if (!data.handlers) { return; }
  461. if (_.isArray(type)) {
  462. return _handleMultipleEvents(module.exports.off, elem, type, fn);
  463. }
  464. // Utility function
  465. var removeType = function(t){
  466. data.handlers[t] = [];
  467. module.exports.cleanUpEvents(elem,t);
  468. };
  469. // Are we removing all bound events?
  470. if (!type) {
  471. for (var t in data.handlers) removeType(t);
  472. return;
  473. }
  474. var handlers = data.handlers[type];
  475. // If no handlers exist, nothing to unbind
  476. if (!handlers) return;
  477. // If no listener was provided, remove all listeners for type
  478. if (!fn) {
  479. removeType(type);
  480. return;
  481. }
  482. // We're only removing a single handler
  483. if (fn.guid) {
  484. for (var n = 0; n < handlers.length; n++) {
  485. if (handlers[n].guid === fn.guid) {
  486. handlers.splice(n--, 1);
  487. }
  488. }
  489. }
  490. module.exports.cleanUpEvents(elem, type);
  491. };
  492. /**
  493. * Clean up the listener cache and dispatchers
  494. * @param {Element|Object} elem Element to clean up
  495. * @param {String} type Type of event to clean up
  496. * @private
  497. */
  498. module.exports.cleanUpEvents = function(elem, type) {
  499. var data = Data.getData(elem);
  500. // Remove the events of a particular type if there are none left
  501. if (data.handlers[type].length === 0) {
  502. delete data.handlers[type];
  503. // data.handlers[type] = null;
  504. // Setting to null was causing an error with data.handlers
  505. // Remove the meta-handler from the element
  506. if (elem.removeEventListener) {
  507. elem.removeEventListener(type, data.dispatcher, false);
  508. } else if (elem.detachEvent) {
  509. elem.detachEvent('on' + type, data.dispatcher);
  510. }
  511. }
  512. // Remove the events object if there are no types left
  513. if (_.isEmpty(data.handlers)) {
  514. delete data.handlers;
  515. delete data.dispatcher;
  516. delete data.disabled;
  517. // data.handlers = null;
  518. // data.dispatcher = null;
  519. // data.disabled = null;
  520. }
  521. // Finally remove the expando if there is no data left
  522. if (_.isEmpty(data)) {
  523. Data.removeData(elem);
  524. }
  525. };
  526. /**
  527. * Fix a native event to have standard property values
  528. * @param {Object} event Event object to fix
  529. * @return {Object}
  530. * @private
  531. */
  532. module.exports.fixEvent = function(event) {
  533. function returnTrue() { return true; }
  534. function returnFalse() { return false; }
  535. // Test if fixing up is needed
  536. // Used to check if !event.stopPropagation instead of isPropagationStopped
  537. // But native events return true for stopPropagation, but don't have
  538. // other expected methods like isPropagationStopped. Seems to be a problem
  539. // with the Javascript Ninja code. So we're just overriding all events now.
  540. if (!event || !event.isPropagationStopped) {
  541. var old = event || window.event;
  542. event = {};
  543. // Clone the old object so that we can modify the values event = {};
  544. // IE8 Doesn't like when you mess with native event properties
  545. // Firefox returns false for event.hasOwnProperty('type') and other props
  546. // which makes copying more difficult.
  547. // TODO: Probably best to create a whitelist of event props
  548. for (var key in old) {
  549. // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y
  550. // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation
  551. if (key !== 'layerX' && key !== 'layerY' && key !== 'keyboardEvent.keyLocation') {
  552. // Chrome 32+ warns if you try to copy deprecated returnValue, but
  553. // we still want to if preventDefault isn't supported (IE8).
  554. if (!(key == 'returnValue' && old.preventDefault)) {
  555. event[key] = old[key];
  556. }
  557. }
  558. }
  559. // The event occurred on this element
  560. if (!event.target) {
  561. event.target = event.srcElement || document;
  562. }
  563. // Handle which other element the event is related to
  564. event.relatedTarget = event.fromElement === event.target ?
  565. event.toElement :
  566. event.fromElement;
  567. // Stop the default browser action
  568. event.preventDefault = function () {
  569. if (old.preventDefault) {
  570. old.preventDefault();
  571. }
  572. event.returnValue = false;
  573. event.isDefaultPrevented = returnTrue;
  574. event.defaultPrevented = true;
  575. };
  576. event.isDefaultPrevented = returnFalse;
  577. event.defaultPrevented = false;
  578. // Stop the event from bubbling
  579. event.stopPropagation = function () {
  580. if (old.stopPropagation) {
  581. old.stopPropagation();
  582. }
  583. event.cancelBubble = true;
  584. event.isPropagationStopped = returnTrue;
  585. };
  586. event.isPropagationStopped = returnFalse;
  587. // Stop the event from bubbling and executing other handlers
  588. event.stopImmediatePropagation = function () {
  589. if (old.stopImmediatePropagation) {
  590. old.stopImmediatePropagation();
  591. }
  592. event.isImmediatePropagationStopped = returnTrue;
  593. event.stopPropagation();
  594. };
  595. event.isImmediatePropagationStopped = returnFalse;
  596. // Handle mouse position
  597. if (event.clientX != null) {
  598. var doc = document.documentElement, body = document.body;
  599. event.pageX = event.clientX +
  600. (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
  601. (doc && doc.clientLeft || body && body.clientLeft || 0);
  602. event.pageY = event.clientY +
  603. (doc && doc.scrollTop || body && body.scrollTop || 0) -
  604. (doc && doc.clientTop || body && body.clientTop || 0);
  605. }
  606. // Handle key presses
  607. event.which = event.charCode || event.keyCode;
  608. // Fix button for mouse clicks:
  609. // 0 == left; 1 == middle; 2 == right
  610. if (event.button != null) {
  611. event.button = (event.button & 1 ? 0 :
  612. (event.button & 4 ? 1 :
  613. (event.button & 2 ? 2 : 0)));
  614. }
  615. }
  616. // Returns fixed-up instance
  617. return event;
  618. };
  619. /**
  620. * Trigger an event for an element
  621. * @param {Element|Object} elem Element to trigger an event on
  622. * @param {Event|Object|String} event A string (the type) or an event object with a type attribute
  623. * @private
  624. */
  625. module.exports.trigger = function(elem, event) {
  626. // Fetches element data and a reference to the parent (for bubbling).
  627. // Don't want to add a data object to cache for every parent,
  628. // so checking hasData first.
  629. var elemData = (Data.hasData(elem)) ? Data.getData(elem) : {};
  630. var parent = elem.parentNode || elem.ownerDocument;
  631. // type = event.type || event,
  632. // handler;
  633. // If an event name was passed as a string, creates an event out of it
  634. if (typeof event === 'string') {
  635. var paramData = null;
  636. if(elem.paramData){
  637. paramData = elem.paramData;
  638. elem.paramData = null;
  639. elem.removeAttribute(paramData);
  640. }
  641. event = { type:event, target:elem, paramData:paramData };
  642. }
  643. // Normalizes the event properties.
  644. event = module.exports.fixEvent(event);
  645. // If the passed element has a dispatcher, executes the established handlers.
  646. if (elemData.dispatcher) {
  647. elemData.dispatcher.call(elem, event);
  648. }
  649. // Unless explicitly stopped or the event does not bubble (e.g. media events)
  650. // recursively calls this function to bubble the event up the DOM.
  651. if (parent && !event.isPropagationStopped() && event.bubbles !== false) {
  652. module.exports.trigger(parent, event);
  653. // If at the top of the DOM, triggers the default action unless disabled.
  654. } else if (!parent && !event.defaultPrevented) {
  655. var targetData = Data.getData(event.target);
  656. // Checks if the target has a default action for this event.
  657. if (event.target[event.type]) {
  658. // Temporarily disables event dispatching on the target as we have already executed the handler.
  659. targetData.disabled = true;
  660. // Executes the default action.
  661. if (typeof event.target[event.type] === 'function') {
  662. event.target[event.type]();
  663. }
  664. // Re-enables event dispatching.
  665. targetData.disabled = false;
  666. }
  667. }
  668. // Inform the triggerer if the default was prevented by returning false
  669. return !event.defaultPrevented;
  670. };
  671. /**
  672. * Trigger a listener only once for an event
  673. * @param {Element|Object} elem Element or object to
  674. * @param {String|Array} type
  675. * @param {Function} fn
  676. * @private
  677. */
  678. module.exports.one = function(elem, type, fn) {
  679. if (_.isArray(type)) {
  680. return _handleMultipleEvents(module.exports.one, elem, type, fn);
  681. }
  682. var func = function(){
  683. module.exports.off(elem, type, func);
  684. fn.apply(this, arguments);
  685. };
  686. // copy the guid to the new function so it can removed using the original function's ID
  687. func.guid = fn.guid = fn.guid || Data.guid();
  688. module.exports.on(elem, type, func);
  689. };
  690. /**
  691. * Loops through an array of event types and calls the requested method for each type.
  692. * @param {Function} fn The event method we want to use.
  693. * @param {Element|Object} elem Element or object to bind listeners to
  694. * @param {String} type Type of event to bind to.
  695. * @param {Function} callback Event listener.
  696. * @private
  697. */
  698. function _handleMultipleEvents(fn, elem, type, callback) {
  699. _.each(type, function(type) {
  700. fn(elem, type, callback); //Call the event method for each one of the types
  701. });
  702. }
  703. },{"./data":4,"./object":10}],7:[function(require,module,exports){
  704. var Data = require('./data');
  705. module.exports.bind = function(context, fn, uid) {
  706. // Make sure the function has a unique ID
  707. if (!fn.guid) { fn.guid = Data.guid(); }
  708. // Create the new function that changes the context
  709. var ret = function() {
  710. return fn.apply(context, arguments);
  711. };
  712. // Allow for the ability to individualize this function
  713. // Needed in the case where multiple objects might share the same prototype
  714. // IF both items add an event listener with the same function, then you try to remove just one
  715. // it will remove both because they both have the same guid.
  716. // when using this, you need to use the bind method when you remove the listener as well.
  717. // currently used in text tracks
  718. ret.guid = (uid) ? uid + '_' + fn.guid : fn.guid;
  719. return ret;
  720. };
  721. },{"./data":4}],8:[function(require,module,exports){
  722. var Url = require('./url');
  723. /**
  724. * Simple http request for retrieving external files (e.g. text tracks)
  725. * @param {String} url URL of resource
  726. * @param {Function} onSuccess Success callback
  727. * @param {Function=} onError Error callback
  728. * @param {Boolean=} withCredentials Flag which allow credentials
  729. * @private
  730. */
  731. module.exports.get = function(url, onSuccess, onError, withCredentials){
  732. var fileUrl, request, urlInfo, winLoc, crossOrigin;
  733. onError = onError || function(){};
  734. if (typeof XMLHttpRequest === 'undefined') {
  735. // Shim XMLHttpRequest for older IEs
  736. window.XMLHttpRequest = function () {
  737. try { return new window.ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch (e) {}
  738. try { return new window.ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch (f) {}
  739. try { return new window.ActiveXObject('Msxml2.XMLHTTP'); } catch (g) {}
  740. throw new Error('This browser does not support XMLHttpRequest.');
  741. };
  742. }
  743. request = new XMLHttpRequest();
  744. urlInfo = Url.parseUrl(url);
  745. winLoc = window.location;
  746. // check if url is for another domain/origin
  747. // ie8 doesn't know location.origin, so we won't rely on it here
  748. crossOrigin = (urlInfo.protocol + urlInfo.host) !== (winLoc.protocol + winLoc.host);
  749. // Use XDomainRequest for IE if XMLHTTPRequest2 isn't available
  750. // 'withCredentials' is only available in XMLHTTPRequest2
  751. // Also XDomainRequest has a lot of gotchas, so only use if cross domain
  752. if(crossOrigin && window.XDomainRequest && !('withCredentials' in request)) {
  753. request = new window.XDomainRequest();
  754. request.onload = function() {
  755. onSuccess(request.responseText);
  756. };
  757. request.onerror = onError;
  758. // these blank handlers need to be set to fix ie9 http://cypressnorth.com/programming/internet-explorer-aborting-ajax-requests-fixed/
  759. request.onprogress = function() {};
  760. request.ontimeout = onError;
  761. // XMLHTTPRequest
  762. } else {
  763. fileUrl = (urlInfo.protocol == 'file:' || winLoc.protocol == 'file:');
  764. request.onreadystatechange = function() {
  765. if (request.readyState === 4) {
  766. if (request.status === 200 || fileUrl && request.status === 0) {
  767. onSuccess(request.responseText);
  768. } else {
  769. onError(request.responseText);
  770. }
  771. }
  772. };
  773. }
  774. // open the connection
  775. try {
  776. // Third arg is async, or ignored by XDomainRequest
  777. request.open('GET', url, true);
  778. // withCredentials only supported by XMLHttpRequest2
  779. if(withCredentials) {
  780. request.withCredentials = true;
  781. }
  782. } catch(e) {
  783. onError(e);
  784. return;
  785. }
  786. // send the request
  787. try {
  788. request.send();
  789. } catch(e) {
  790. onError(e);
  791. }
  792. };
  793. /**
  794. * jsonp请求
  795. */
  796. module.exports.jsonp = function(url, onSuccess, onError) {
  797. var callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());
  798. var script = document.createElement('script');
  799. script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'callback=' + callbackName;
  800. script.onerror = function() {
  801. delete window[callbackName];
  802. document.body.removeChild(script);
  803. onError();
  804. };
  805. // 防止接口返回不支持jsonp时的script标签堆积
  806. script.onload = function() {
  807. setTimeout(function() {
  808. if (window[callbackName]) {
  809. delete window[callbackName];
  810. document.body.removeChild(script);
  811. }
  812. }, 0);
  813. };
  814. window[callbackName] = function(data) {
  815. delete window[callbackName];
  816. document.body.removeChild(script);
  817. onSuccess(data);
  818. };
  819. document.body.appendChild(script);
  820. }
  821. },{"./url":13}],9:[function(require,module,exports){
  822. /**
  823. * @fileoverview 根据配置渲染ui组件在父级组件中的layout
  824. * @author 首作<aloysious.ld@taobao.com>
  825. * @date 2015-01-12
  826. *
  827. * ui组件与layout相关的配置项
  828. * align {String} 'cc' 绝对居中
  829. * | 'tl' 左上对齐,组件向左浮动,并以左上角作为偏移原点
  830. * | 'tr' 右上对齐,组件向右浮动,并以右上角作为偏移原点
  831. * | 'tlabs' 以左上角偏移,相对于父级组件绝对定位,不受同级组件的占位影响
  832. * | 'trabs' 以右上角偏移,相对于父级组件绝对定位,不受同级组件的占位影响
  833. * | 'blabs' 以左下角偏移,相对于父级组件绝对定位,不受同级组件的占位影响
  834. * | 'brabs' 以右下角偏移,相对于父级组件绝对定位,不受同级组件的占位影响
  835. * x {Number} x轴的偏移量,align为'cc'时无效
  836. * y {Number} y轴的偏移量,align为'cc'时无效
  837. */
  838. var Dom = require('./dom');
  839. /**
  840. * 根据配置渲染dom元素的layout
  841. * @param el {HTMLElement} dom元素
  842. * @param opt {Object} layout配置对象
  843. */
  844. module.exports.render = function(el, opt) {
  845. var align = opt.align ? opt.align : 'tl',
  846. x = opt.x ? opt.x : 0,
  847. y = opt.y ? opt.y : 0;
  848. if (align === 'tl') {
  849. Dom.css(el, {
  850. 'float': 'left',
  851. 'margin-left': x + 'px',
  852. 'margin-top': y+ 'px'
  853. });
  854. } else if (align === 'tr') {
  855. Dom.css(el, {
  856. 'float': 'right',
  857. 'margin-right': x + 'px',
  858. 'margin-top': y+ 'px'
  859. });
  860. } else if (align === 'tlabs') {
  861. Dom.css(el, {
  862. 'position': 'absolute',
  863. 'left': x + 'px',
  864. 'top': y + 'px'
  865. });
  866. } else if (align === 'trabs') {
  867. Dom.css(el, {
  868. 'position': 'absolute',
  869. 'right': x + 'px',
  870. 'top': y + 'px'
  871. });
  872. } else if (align === 'blabs') {
  873. Dom.css(el, {
  874. 'position': 'absolute',
  875. 'left': x + 'px',
  876. 'bottom': y + 'px'
  877. });
  878. } else if (align === 'brabs') {
  879. Dom.css(el, {
  880. 'position': 'absolute',
  881. 'right': x + 'px',
  882. 'bottom': y + 'px'
  883. });
  884. } else if (align === 'cc') {
  885. Dom.css(el, {
  886. 'position': 'absolute',
  887. 'left': '50%',
  888. 'top': '50%',
  889. 'margin-top': ( el.offsetHeight / -2 ) + 'px',
  890. 'margin-left': ( el.offsetWidth / -2 ) + 'px'
  891. });
  892. }
  893. };
  894. },{"./dom":5}],10:[function(require,module,exports){
  895. var hasOwnProp = Object.prototype.hasOwnProperty;
  896. /**
  897. * Object.create shim for prototypal inheritance
  898. *
  899. * https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
  900. *
  901. * @function
  902. * @param {Object} obj Object to use as prototype
  903. * @private
  904. */
  905. module.exports.create = Object.create || function(obj){
  906. //Create a new function called 'F' which is just an empty object.
  907. function F() {}
  908. //the prototype of the 'F' function should point to the
  909. //parameter of the anonymous function.
  910. F.prototype = obj;
  911. //create a new constructor function based off of the 'F' function.
  912. return new F();
  913. };
  914. /**
  915. * Loop through each property in an object and call a function
  916. * whose arguments are (key,value)
  917. * @param {Object} obj Object of properties
  918. * @param {Function} fn Function to be called on each property.
  919. * @this {*}
  920. * @private
  921. */
  922. module.exports.isArray = function(arr){
  923. return Object.prototype.toString.call(arg) === '[object Array]';
  924. }
  925. module.exports.isEmpty = function(obj) {
  926. for (var prop in obj) {
  927. // Inlude null properties as empty.
  928. if (obj[prop] !== null) {
  929. return false;
  930. }
  931. }
  932. return true;
  933. };
  934. module.exports.each = function(obj, fn, context){
  935. //
  936. if(module.exports.isArray(obj)){
  937. for (var i = 0, len = obj.length; i < len; ++i) {
  938. if (fn.call(context || this, obj[i], i) === false) {
  939. break;
  940. }
  941. }
  942. }else{
  943. for (var key in obj) {
  944. if (hasOwnProp.call(obj, key)) {
  945. // if (key=="code") {
  946. // console.log(obj);
  947. // };
  948. // console.log(key);
  949. // console.log(obj[key]);
  950. if (fn.call(context || this, key, obj[key]) === false) {
  951. break;
  952. }
  953. }
  954. }
  955. }
  956. return obj;
  957. };
  958. /**
  959. * Merge two objects together and return the original.
  960. * @param {Object} obj1
  961. * @param {Object} obj2
  962. * @return {Object}
  963. * @private
  964. */
  965. module.exports.merge = function(obj1, obj2){
  966. if (!obj2) { return obj1; }
  967. for (var key in obj2){
  968. if (hasOwnProp.call(obj2, key)) {
  969. obj1[key] = obj2[key];
  970. }
  971. }
  972. return obj1;
  973. };
  974. /**
  975. * Merge two objects, and merge any properties that are objects
  976. * instead of just overwriting one. Uses to merge options hashes
  977. * where deeper default settings are important.
  978. * @param {Object} obj1 Object to override
  979. * @param {Object} obj2 Overriding object
  980. * @return {Object} New object. Obj1 and Obj2 will be untouched.
  981. * @private
  982. */
  983. module.exports.deepMerge = function(obj1, obj2){
  984. var key, val1, val2;
  985. // make a copy of obj1 so we're not ovewriting original values.
  986. // like prototype.options_ and all sub options objects
  987. obj1 = module.exports.copy(obj1);
  988. for (key in obj2){
  989. if (hasOwnProp.call(obj2, key)) {
  990. val1 = obj1[key];
  991. val2 = obj2[key];
  992. // Check if both properties are pure objects and do a deep merge if so
  993. if (module.exports.isPlain(val1) && module.exports.isPlain(val2)) {
  994. obj1[key] = module.exports.deepMerge(val1, val2);
  995. } else {
  996. obj1[key] = obj2[key];
  997. }
  998. }
  999. }
  1000. return obj1;
  1001. };
  1002. /**
  1003. * Make a copy of the supplied object
  1004. * @param {Object} obj Object to copy
  1005. * @return {Object} Copy of object
  1006. * @private
  1007. */
  1008. module.exports.copy = function(obj){
  1009. return module.exports.merge({}, obj);
  1010. };
  1011. /**
  1012. * Check if an object is plain, and not a dom node or any object sub-instance
  1013. * @param {Object} obj Object to check
  1014. * @return {Boolean} True if plain, false otherwise
  1015. * @private
  1016. */
  1017. module.exports.isPlain = function(obj){
  1018. return !!obj
  1019. && typeof obj === 'object'
  1020. && obj.toString() === '[object Object]'
  1021. && obj.constructor === Object;
  1022. };
  1023. /**
  1024. * Check if an object is Array
  1025. * Since instanceof Array will not work on arrays created in another frame we need to use Array.isArray, but since IE8 does not support Array.isArray we need this shim
  1026. * @param {Object} obj Object to check
  1027. * @return {Boolean} True if plain, false otherwise
  1028. * @private
  1029. */
  1030. module.exports.isArray = Array.isArray || function(arr) {
  1031. return Object.prototype.toString.call(arr) === '[object Array]';
  1032. };
  1033. module.exports.unescape = function(str) {
  1034. return str.replace(/&([^;]+);/g, function(m,$1) {
  1035. return {
  1036. 'amp': '&',
  1037. 'lt': '<',
  1038. 'gt': '>',
  1039. 'quot': '"',
  1040. '#x27': "'",
  1041. '#x60': '`'
  1042. }[$1.toLowerCase()] || m;
  1043. });
  1044. };
  1045. },{}],11:[function(require,module,exports){
  1046. var _ = require('./object');
  1047. var oo = function(){};
  1048. // Manually exporting module.exports['oo'] here for Closure Compiler
  1049. // because of the use of the extend/create class methods
  1050. // If we didn't do this, those functions would get flattend to something like
  1051. // `a = ...` and `this.prototype` would refer to the global object instead of
  1052. // oo
  1053. var oo = function() {};
  1054. /**
  1055. * Create a new object that inherits from this Object
  1056. *
  1057. * var Animal = oo.extend();
  1058. * var Horse = Animal.extend();
  1059. *
  1060. * @param {Object} props Functions and properties to be applied to the
  1061. * new object's prototype
  1062. * @return {module.exports.oo} An object that inherits from oo
  1063. * @this {*}
  1064. */
  1065. oo.extend = function(props){
  1066. var init, subObj;
  1067. props = props || {};
  1068. // Set up the constructor using the supplied init method
  1069. // or using the init of the parent object
  1070. // Make sure to check the unobfuscated version for external libs
  1071. init = props['init'] || props.init || this.prototype['init'] || this.prototype.init || function(){};
  1072. // In Resig's simple class inheritance (previously used) the constructor
  1073. // is a function that calls `this.init.apply(arguments)`
  1074. // However that would prevent us from using `ParentObject.call(this);`
  1075. // in a Child constuctor because the `this` in `this.init`
  1076. // would still refer to the Child and cause an inifinite loop.
  1077. // We would instead have to do
  1078. // `ParentObject.prototype.init.apply(this, argumnents);`
  1079. // Bleh. We're not creating a _super() function, so it's good to keep
  1080. // the parent constructor reference simple.
  1081. subObj = function(){
  1082. init.apply(this, arguments);
  1083. };
  1084. // Inherit from this object's prototype
  1085. subObj.prototype = _.create(this.prototype);
  1086. // Reset the constructor property for subObj otherwise
  1087. // instances of subObj would have the constructor of the parent Object
  1088. subObj.prototype.constructor = subObj;
  1089. // Make the class extendable
  1090. subObj.extend = oo.extend;
  1091. // Make a function for creating instances
  1092. subObj.create = oo.create;
  1093. // Extend subObj's prototype with functions and other properties from props
  1094. for (var name in props) {
  1095. if (props.hasOwnProperty(name)) {
  1096. subObj.prototype[name] = props[name];
  1097. }
  1098. }
  1099. return subObj;
  1100. };
  1101. /**
  1102. * Create a new instace of this Object class
  1103. *
  1104. * var myAnimal = Animal.create();
  1105. *
  1106. * @return {module.exports.oo} An instance of a oo subclass
  1107. * @this {*}
  1108. */
  1109. oo.create = function(){
  1110. // Create a new object that inherits from this object's prototype
  1111. var inst = _.create(this.prototype);
  1112. // Apply this constructor function to the new object
  1113. this.apply(inst, arguments);
  1114. // Return the new object
  1115. return inst;
  1116. };
  1117. module.exports = oo;
  1118. },{"./object":10}],12:[function(require,module,exports){
  1119. module.exports.USER_AGENT = navigator.userAgent;
  1120. /**
  1121. * Device is an iPhone
  1122. * @type {Boolean}
  1123. * @constant
  1124. * @private
  1125. */
  1126. module.exports.IS_IPHONE = (/iPhone/i).test(module.exports.USER_AGENT);
  1127. module.exports.IS_IPAD = (/iPad/i).test(module.exports.USER_AGENT);
  1128. module.exports.IS_IPOD = (/iPod/i).test(module.exports.USER_AGENT);
  1129. module.exports.IS_IOS = module.exports.IS_IPHONE || module.exports.IS_IPAD || module.exports.IS_IPOD;
  1130. module.exports.IOS_VERSION = (function(){
  1131. var match = module.exports.USER_AGENT.match(/OS (\d+)_/i);
  1132. if (match && match[1]) { return match[1]; }
  1133. })();
  1134. module.exports.IS_ANDROID = (/Android/i).test(module.exports.USER_AGENT);
  1135. module.exports.ANDROID_VERSION = (function() {
  1136. // This matches Android Major.Minor.Patch versions
  1137. // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
  1138. var match = module.exports.USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i),
  1139. major,
  1140. minor;
  1141. if (!match) {
  1142. return null;
  1143. }
  1144. major = match[1] && parseFloat(match[1]);
  1145. minor = match[2] && parseFloat(match[2]);
  1146. if (major && minor) {
  1147. return parseFloat(match[1] + '.' + match[2]);
  1148. } else if (major) {
  1149. return major;
  1150. } else {
  1151. return null;
  1152. }
  1153. })();
  1154. // Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser
  1155. module.exports.IS_OLD_ANDROID = module.exports.IS_ANDROID && (/webkit/i).test(module.exports.USER_AGENT) && module.exports.ANDROID_VERSION < 2.3;
  1156. module.exports.IS_FIREFOX = (/Firefox/i).test(module.exports.USER_AGENT);
  1157. module.exports.IS_CHROME = (/Chrome/i).test(module.exports.USER_AGENT);
  1158. module.exports.TOUCH_ENABLED = !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch);
  1159. module.exports.IS_MOBILE = module.exports.IS_IOS || module.exports.IS_ANDROID;
  1160. module.exports.IS_PC = !module.exports.IS_MOBILE;
  1161. },{}],13:[function(require,module,exports){
  1162. var Dom = require('./dom');
  1163. /**
  1164. * Get abosolute version of relative URL. Used to tell flash correct URL.
  1165. * http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
  1166. * @param {String} url URL to make absolute
  1167. * @return {String} Absolute URL
  1168. * @private
  1169. */
  1170. module.exports.getAbsoluteURL = function(url){
  1171. // Check if absolute URL
  1172. if (!url.match(/^https?:\/\//)) {
  1173. // Convert to absolute URL. Flash hosted off-site needs an absolute URL.
  1174. url = Dom.createEl('div', {
  1175. innerHTML: '<a href="'+url+'">x</a>'
  1176. }).firstChild.href;
  1177. }
  1178. return url;
  1179. };
  1180. /**
  1181. * Resolve and parse the elements of a URL
  1182. * @param {String} url The url to parse
  1183. * @return {Object} An object of url details
  1184. */
  1185. module.exports.parseUrl = function(url) {
  1186. var div, a, addToBody, props, details;
  1187. props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host'];
  1188. // add the url to an anchor and let the browser parse the URL
  1189. a = Dom.createEl('a', { href: url });
  1190. // IE8 (and 9?) Fix
  1191. // ie8 doesn't parse the URL correctly until the anchor is actually
  1192. // added to the body, and an innerHTML is needed to trigger the parsing
  1193. addToBody = (a.host === '' && a.protocol !== 'file:');
  1194. if (addToBody) {
  1195. div = Dom.createEl('div');
  1196. div.innerHTML = '<a href="'+url+'"></a>';
  1197. a = div.firstChild;
  1198. // prevent the div from affecting layout
  1199. div.setAttribute('style', 'display:none; position:absolute;');
  1200. document.body.appendChild(div);
  1201. }
  1202. // Copy the specific URL properties to a new object
  1203. // This is also needed for IE8 because the anchor loses its
  1204. // properties when it's removed from the dom
  1205. details = {};
  1206. for (var i = 0; i < props.length; i++) {
  1207. details[props[i]] = a[props[i]];
  1208. }
  1209. if (addToBody) {
  1210. document.body.removeChild(div);
  1211. }
  1212. return details;
  1213. };
  1214. },{"./dom":5}],14:[function(require,module,exports){
  1215. // 将秒格式化为00:00:00格式
  1216. module.exports.formatTime = function(seconds) {
  1217. var raw = Math.round(seconds),
  1218. hour,
  1219. min,
  1220. sec;
  1221. hour = Math.floor(raw / 3600);
  1222. raw = raw % 3600;
  1223. min = Math.floor(raw / 60);
  1224. sec = raw % 60;
  1225. if (hour === Infinity || isNaN(hour)
  1226. || min === Infinity || isNaN(min)
  1227. || sec === Infinity || isNaN(sec)) {
  1228. return false;
  1229. }
  1230. hour = hour >= 10 ? hour: '0' + hour;
  1231. min = min >= 10 ? min: '0' + min;
  1232. sec = sec >= 10 ? sec: '0' + sec;
  1233. return (hour === '00' ? '': (hour + ':')) + min + ':' + sec;
  1234. },
  1235. // 将00:00:00格式解析为秒
  1236. module.exports.parseTime = function(timeStr) {
  1237. var timeArr = timeStr.split(':'),
  1238. h = 0,
  1239. m = 0,
  1240. s = 0;
  1241. if (timeArr.length === 3) {
  1242. h = timeArr[0];
  1243. m = timeArr[1];
  1244. s = timeArr[2];
  1245. } else if (timeArr.length === 2) {
  1246. m = timeArr[0];
  1247. s = timeArr[1];
  1248. } else if (timeArr.length === 1) {
  1249. s = timeArr[0];
  1250. }
  1251. h = parseInt(h, 10);
  1252. m = parseInt(m, 10);
  1253. // 秒可能有小数位,需要向上取整
  1254. s = Math.ceil(parseFloat(s));
  1255. return h * 3600 + m * 60 + s;
  1256. }
  1257. },{}],15:[function(require,module,exports){
  1258. var oo = require('../lib/oo');
  1259. var _ = require('../lib/object');
  1260. var Cookie = require('../lib/cookie');
  1261. var Data = require('../lib/data');
  1262. var IO = require('../lib/io');
  1263. var UA = require('../lib/ua');
  1264. var CONF = require('../config');
  1265. var EVENT = {
  1266. 'INIT': 1001, // 初始化
  1267. 'CLOSE': 1002, // 关闭播放器
  1268. 'PLAY': 2001, // 开始播放
  1269. 'STOP': 2002, // 停止,h5下指播放完毕
  1270. 'PAUSE': 2003, // 暂停
  1271. 'RECOVER': 2010, // 暂停恢复
  1272. 'SEEK': 2004, // 拖动
  1273. 'SEEK_END': 2011, // 拖动结束,h5暂时不实现
  1274. 'FULLSREEM': 2005, // 全屏
  1275. 'QUITFULLSCREEM': 2006, // 退出全屏
  1276. 'UNDERLOAD': 3002, // 卡顿
  1277. 'LOADED': 3001, // 卡顿恢复
  1278. 'RESOLUTION': 2007, // 切换清晰度,h5暂时不实现
  1279. 'RESOLUTION_DONE': 2009, // 切换清晰度完成,h5暂时不实现
  1280. 'HEARTBEAT': 9001, // 心跳,5秒间隔
  1281. 'ERROR': 4001 // 发生错误
  1282. };
  1283. //实时监测id
  1284. var checkIntervalInt;
  1285. var Monitor = oo.extend({
  1286. /**
  1287. * @param player {Player} 播放器实例
  1288. * @param options {Object} 监控的配置参数
  1289. * - lv (log_version) 日志版本,初始版本为1
  1290. * - b (bussiness_id) 业务方id, 初始为prism_aliyun, 输入参数from
  1291. * - lm (live_mode) 直播点播区分:prism_live,prism_vod
  1292. * - t (terminal_type) 终端类型
  1293. * - pv (player_version) 播放器版本号,1
  1294. * - uuid (uuid) 设备或机器id,h5保存在cookie中
  1295. * - v (video_id) 视频id
  1296. * - u (user_id) 用户id
  1297. * - s (session_id) 播放行为id,一个视频正常播放后需要重置(动态生成)
  1298. * - e (event_id) 事件id(动态生成)
  1299. * - args (args) 事件携带参数
  1300. * - d (definition) 清晰度
  1301. * - cdn_ip (cdn_ip) 下载数据的cdn地址,h5无法设置host,这个字段无用,写死为0.0.0.0
  1302. * - ct (client_timestamp) 客户端事件戳
  1303. */
  1304. init: function(player, options) {
  1305. this.player = player;
  1306. var po=this.player.getOptions();
  1307. var h5_log_version = "1";
  1308. var h5_bussiness_id = options.from ? options.from : "prism_aliyun";
  1309. var h5_live_mode = po.isLive?"prism_live":"prism_vod";
  1310. // default: pcweb
  1311. var h5_terminal_type = "pc";
  1312. if (UA.IS_IPAD) {
  1313. h5_terminal_type = "pad";
  1314. } else if (UA.IS_IPHONE) {
  1315. h5_terminal_type = "iphone";
  1316. } else if (UA.IS_ANDROID) {
  1317. h5_terminal_type = "andorid";
  1318. }
  1319. var h5_device_model = UA.IS_PC?'pc_h5':'h5';
  1320. var h5_player_version = CONF.h5Version;
  1321. var h5_uuid = this._getUuid();
  1322. var h5_video_id = po.source ? encodeURIComponent(po.source) : options.video_id;
  1323. var h5_user_id = "0";
  1324. var h5_session_id = this.sessionId;
  1325. var h5_event_id = "0";
  1326. var h5_args = "0";
  1327. var h5_definition = "custom";
  1328. var h5_cdn_ip = "0.0.0.0";
  1329. var h5_client_timestamp = new Date().getTime();
  1330. this.opt = {
  1331. APIVersion: '0.6.0',
  1332. lv: h5_log_version, //log_version
  1333. b: h5_bussiness_id, //business_id
  1334. lm: h5_live_mode, //live_mode
  1335. t: h5_terminal_type, //terminal_type
  1336. m: h5_device_model, //device_model
  1337. pv: h5_player_version, //player_version
  1338. uuid: h5_uuid, //uuid
  1339. v: h5_video_id, //video_id
  1340. u: h5_user_id, //user_id
  1341. s: h5_session_id, //session_id
  1342. e: h5_event_id, //event_id
  1343. args: h5_args, //args
  1344. d: h5_definition, //definition
  1345. cdn_ip: h5_cdn_ip, //cdn_ip
  1346. ct: h5_client_timestamp, //client_timestamp
  1347. };
  1348. this.bindEvent();
  1349. },
  1350. //更新视频信息,当播放器实例不变,播放内容更换时使用
  1351. updateVideoInfo:function(options){
  1352. var po=this.player.getOptions();
  1353. var h5_log_version = "1";
  1354. var h5_bussiness_id = options.from ? options.from : "prism_aliyun";
  1355. var h5_live_mode = po.isLive?"prism_live":"prism_vod";
  1356. // default: pcweb
  1357. var h5_terminal_type = "pc";
  1358. if (UA.IS_IPAD) {
  1359. h5_terminal_type = "pad";
  1360. } else if (UA.IS_IPHONE) {
  1361. h5_terminal_type = "iphone";
  1362. } else if (UA.IS_ANDROID) {
  1363. h5_terminal_type = "andorid";
  1364. }
  1365. var h5_device_model = UA.IS_PC?'pc_h5':'h5';
  1366. var h5_player_version = CONF.h5Version;
  1367. var h5_uuid = this._getUuid();
  1368. var h5_video_id = po.source ? encodeURIComponent(po.source) : options.video_id;
  1369. var h5_user_id = "0";
  1370. var h5_session_id = this.sessionId;
  1371. var h5_event_id = "0";
  1372. var h5_args = "0";
  1373. var h5_definition = "custom";
  1374. var h5_cdn_ip = "0.0.0.0";
  1375. var h5_client_timestamp = new Date().getTime();
  1376. this.opt = {
  1377. APIVersion: '0.6.0',
  1378. lv: h5_log_version, //log_version
  1379. b: h5_bussiness_id, //business_id
  1380. lm: h5_live_mode, //live_mode
  1381. t: h5_terminal_type, //terminal_type
  1382. m: h5_device_model, //device_model
  1383. pv: h5_player_version, //player_version
  1384. uuid: h5_uuid, //uuid
  1385. v: h5_video_id, //video_id
  1386. u: h5_user_id, //user_id
  1387. s: h5_session_id, //session_id
  1388. e: h5_event_id, //event_id
  1389. args: h5_args, //args
  1390. d: h5_definition, //definition
  1391. cdn_ip: h5_cdn_ip, //cdn_ip
  1392. ct: h5_client_timestamp, //client_timestamp
  1393. };
  1394. },
  1395. //event
  1396. bindEvent: function() {
  1397. var that = this;
  1398. this.player.on('init', function() {that._onPlayerInit();});
  1399. window.addEventListener('beforeunload', function() {that._onPlayerClose();});
  1400. this.player.on('ready', function() {that._onPlayerReady();});
  1401. this.player.on('ended', function() {that._onPlayerFinish();});
  1402. this.player.on('play', function() {that._onPlayerPlay();});
  1403. this.player.on('pause', function() {that._onPlayerPause();});
  1404. //this.player.on('seeking', function(e){that._onPlayerSeekStart(e);});
  1405. //this.player.on('seeked', function(e){that._onPlayerSeekEnd(e);});
  1406. this.player.on('seekStart', function(e){that._onPlayerSeekStart(e);});
  1407. this.player.on('seekEnd', function(e){that._onPlayerSeekEnd(e);});
  1408. this.player.on('waiting', function() {that._onPlayerLoaded();});
  1409. this.player.on('canplaythrough', function() {that._onPlayerUnderload();});
  1410. //this.player.on('canplay', function() {that._onPlayerUnderload();});
  1411. //this.player.on('timeupdate', function() {that._onPlayerHeartBeat();});
  1412. this.player.on('error', function() {that._onPlayerError();});
  1413. //this.player.on('fullscreenchange', function() {that._onFullscreenChange);});
  1414. //this.player.on('qualitychange', function() {that._onPlayerSwitchResolution);});
  1415. checkIntervalInt=setInterval(function() {
  1416. // 卡顿开始
  1417. if (that.player.readyState() === 2 || that.player.readyState() === 3) {
  1418. that._onPlayerLoaded();
  1419. //alert("state_buffer");
  1420. // 卡顿恢复
  1421. } else if (that.player.readyState() === 4) {
  1422. that._onPlayerUnderload();
  1423. }
  1424. }, 100);
  1425. },
  1426. removeEvent:function(){
  1427. var that = this;
  1428. this.player.off('init');
  1429. this.player.off('ready');
  1430. this.player.off('ended');
  1431. this.player.off('play');
  1432. this.player.off('pause');
  1433. this.player.off('seekStart');
  1434. this.player.off('seekEnd');
  1435. this.player.off('canplaythrough');
  1436. //this.player.off('timeupdate', function() {that._onPlayerHeartBeat();});
  1437. this.player.off('error');
  1438. //this.player.off('fullscreenchange');
  1439. //this.player.off('qualitychange');
  1440. clearInterval(checkIntervalInt);
  1441. },
  1442. //init
  1443. _onPlayerInit: function() {
  1444. // 重置sessionId
  1445. this.sessionId = Data.guid();
  1446. this._log('INIT', {});
  1447. this.buffer_flag = 0; //after first play, set 1
  1448. this.pause_flag = 0; //pause status
  1449. },
  1450. //beforeunload
  1451. _onPlayerClose: function() {
  1452. this._log('CLOSE', {vt: Math.floor(this.player.getCurrentTime() * 1000)});
  1453. },
  1454. //ready
  1455. _onPlayerReady: function() {
  1456. //保存开始播放时间戳
  1457. this.startTimePlay = new Date().getTime();
  1458. },
  1459. //end
  1460. _onPlayerFinish: function() {
  1461. // 重置sessionId
  1462. this.sessionId = Data.guid();
  1463. this._log('STOP', {vt: Math.floor(this.player.getCurrentTime() * 1000)});
  1464. },
  1465. //play
  1466. _onPlayerPlay: function() {
  1467. //若为autoplay,点击开始才上报2001
  1468. if (!this.buffer_flag && this.player._options.autoplay) {
  1469. this.first_play_time = new Date().getTime();
  1470. this._log('PLAY', {dsm: 'fix', vt: 0, cost: this.first_play_time - this.player.getReadyTime()});
  1471. this.buffer_flag = 1;
  1472. return;
  1473. }
  1474. //忽略播放前的暂停
  1475. if (!this.buffer_flag) return;
  1476. //若非暂停则返回
  1477. if (!this.pause_flag) return;
  1478. this.pause_flag = 0;
  1479. this.pauseEndTime = new Date().getTime();
  1480. this._log('RECOVER', {vt: Math.floor(this.player.getCurrentTime() * 1000), cost: this.pauseEndTime - this.pauseTime});
  1481. },
  1482. //pause
  1483. _onPlayerPause: function() {
  1484. //忽略播放前的暂停
  1485. if (!this.buffer_flag) return;
  1486. //未赋值不记录暂停
  1487. if (!this.startTimePlay) return;
  1488. //忽略seek时的暂停
  1489. if (this.seeking) return;
  1490. this.pause_flag = 1;
  1491. this.pauseTime = new Date().getTime();
  1492. this._log('PAUSE', {vt: Math.floor(this.player.getCurrentTime() * 1000)});
  1493. },
  1494. //seekstart
  1495. _onPlayerSeekStart: function(e) {
  1496. this.seekStartTime = e.paramData.fromTime;
  1497. this.seeking = true;
  1498. this.seekStartStamp = new Date().getTime();
  1499. },
  1500. //seekend
  1501. _onPlayerSeekEnd: function(e) {
  1502. this.seekEndStamp = new Date().getTime();
  1503. this._log('SEEK', {drag_from_timestamp: Math.floor(this.seekStartTime * 1000), drag_to_timestamp: Math.floor(e.paramData.toTime * 1000)});
  1504. this._log('SEEK_END', {vt: Math.floor(this.player.getCurrentTime() * 1000), cost: this.seekEndStamp - this.seekStartStamp });
  1505. this.seeking = false;
  1506. },
  1507. //waiting
  1508. _onPlayerLoaded: function() {
  1509. // 第一次播放前不记录卡顿,卡顿不置位,不产生卡顿恢复
  1510. if (!this.buffer_flag) return;
  1511. //未赋值不记录卡顿
  1512. if (!this.startTimePlay) return;
  1513. // 已经处于卡顿或者拖拽过程中不去记录卡顿
  1514. if (this.stucking || this.seeking) return;
  1515. // 如果卡顿在开始播放1s以内发生则忽略
  1516. this.stuckStartTime = new Date().getTime();
  1517. //console.log(this.stuckStartTime);
  1518. //console.log(this.startTimePlay);
  1519. if ( this.stuckStartTime - this.startTimePlay <= 1000 )
  1520. return;
  1521. //alert("load_buffer");
  1522. this.stucking = true;
  1523. this._log('UNDERLOAD', {vt: Math.floor(this.player.getCurrentTime() * 1000)});
  1524. this.stuckStartTime = new Date().getTime();
  1525. },
  1526. //canplaythrough, canplay:有些浏览器没有
  1527. _onPlayerUnderload: function() { //卡顿恢复
  1528. //第一次恢复,并且非自动播放,认为开始播放,(自动播放会提起load数据,导致上报过早)
  1529. if (!this.buffer_flag && !this.player._options.autoplay) {
  1530. this.first_play_time = new Date().getTime();
  1531. this._log('PLAY', {play_mode: 'fix', vt: 0, cost: this.first_play_time - this.player.getReadyTime()});
  1532. this.buffer_flag = 1;
  1533. return;
  1534. }
  1535. //若未开播,且autoplay,则返回
  1536. if(!this.buffer_flag && this.player._options.autoplay ) return;
  1537. // 如果当前不在卡顿中,或者在拖拽过程中,不应该记录卡顿恢复
  1538. if (!this.stucking || this.seeking) return;
  1539. var currTime = Math.floor(this.player.getCurrentTime() * 1000),
  1540. startTime = this.stuckStartTime || new Date().getTime(),
  1541. cost = Math.floor(new Date().getTime() - startTime);
  1542. if (cost < 0) cost = 0;
  1543. this._log('LOADED', {vt: currTime, cost: cost});
  1544. this.stucking = false;
  1545. },
  1546. _onPlayerHeartBeat: function() {
  1547. // 拖拽过程中不去记录心跳
  1548. if (this.seeking) return;
  1549. var currTime = Math.floor(this.player.getCurrentTime() * 1000),
  1550. that = this;
  1551. if (!this.timer) {
  1552. this.timer = setTimeout(function() {
  1553. !that.seeking && that._log('HEARTBEAT', {progress: currTime});
  1554. clearTimeout(that.timer);
  1555. that.timer = null;
  1556. }, 60000);
  1557. }
  1558. },
  1559. //error
  1560. _onPlayerError: function() {
  1561. var trackerError = {
  1562. 'MEDIA_ERR_NETWORK': -1,
  1563. 'MEDIA_ERR_SRC_NOT_SUPPORTED': -2,
  1564. 'MEDIA_ERR_DECODE': -3
  1565. },
  1566. errorObj = this.player.getError(),
  1567. errorCode = errorObj.code,
  1568. tMsg;
  1569. _.each(errorObj.__proto__, function(k, v) {
  1570. if (v === errorCode) {
  1571. tMsg = k;
  1572. return false;
  1573. }
  1574. });
  1575. if (trackerError[tMsg]) {
  1576. this._log('ERROR', {vt: Math.floor(this.player.getCurrentTime() * 1000), error_code: trackerError[tMsg], error_msg: tMsg});
  1577. }
  1578. },
  1579. _log: function(eventType, extCfg) {
  1580. var cfg = _.copy(this.opt);
  1581. //var url='//log.video.taobao.com/stat/';
  1582. //var url='//videocloud.cn-hangzhou.log.aliyuncs.com/logstores/player/track';
  1583. var url= CONF.logReportTo;
  1584. cfg.e = EVENT[eventType];
  1585. cfg.s = this.sessionId;
  1586. cfg.ct = new Date().getTime();
  1587. var args_params = [];
  1588. _.each(extCfg, function(k, v) {
  1589. args_params.push(k + '=' + v);
  1590. });
  1591. args_params = args_params.join('&');
  1592. if (args_params == "") {
  1593. args_params = "0";
  1594. }
  1595. cfg.args = encodeURIComponent(args_params);
  1596. /*
  1597. if (extCfg.vt) {
  1598. extCfg.vt = Math.round(extCfg.vt);
  1599. }
  1600. if (extCfg.cost) {
  1601. extCfg.cost = Math.round(extCfg.cost);
  1602. }
  1603. extCfg.systs = new Date().getTime();
  1604. cfg = _.merge(cfg, extCfg);
  1605. */
  1606. var params = [];
  1607. _.each(cfg, function(k, v) {
  1608. params.push(k + '=' + v);
  1609. });
  1610. params = params.join('&');
  1611. IO.jsonp(url + '?' + params, function() {}, function() {});
  1612. },
  1613. /**
  1614. * 唯一表示播放器的id缓存在cookie中
  1615. */
  1616. _getUuid: function() {
  1617. // p_h5_u表示prism_h5_uuid
  1618. var uuid = Cookie.get('p_h5_u');
  1619. if (!uuid) {
  1620. uuid = Data.guid();
  1621. Cookie.set('p_h5_u', uuid, 7);
  1622. }
  1623. return uuid;
  1624. }
  1625. });
  1626. module.exports = Monitor;
  1627. },{"../config":1,"../lib/cookie":3,"../lib/data":4,"../lib/io":8,"../lib/object":10,"../lib/oo":11,"../lib/ua":12}],16:[function(require,module,exports){
  1628. /*
  1629. * flash播放器核心类
  1630. */
  1631. var Component = require('../ui/component');
  1632. var Data = require('../lib/data');
  1633. var _ = require('../lib/object');
  1634. var cfg = require('../config');
  1635. //var swfobj=require('../lib/swfobject');
  1636. var FlashPlayer = Component.extend({
  1637. init: function(tag, options) {
  1638. Component.call(this, this, options);
  1639. // 在window下挂载变量,便于flash调用
  1640. this._id = this.id = 'prism-player-' + Data.guid();
  1641. this.tag = tag;
  1642. this._el = this.tag;
  1643. window[this.id] = this;
  1644. var width = '100%';
  1645. var height = '100%';
  1646. // TODO 临时先用日常的
  1647. var swfUrl = '//' + cfg.domain + '/de/prismplayer-flash/' + cfg.flashVersion + '/PrismPlayer.swf';
  1648. var flashVar = this._comboFlashVars();
  1649. var wmode=this._options.wmode?this._options.wmode:"opaque";
  1650. tag.innerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0" width="' + width + '" height="' + height + '" id="' + this.id + '">' +
  1651. '<param name=movie value="' + swfUrl + '">'+
  1652. '<param name=quality value=High>'+
  1653. '<param name="FlashVars" value="' + flashVar + '">' +
  1654. '<param name="WMode" value="'+wmode+'">' +
  1655. '<param name="AllowScriptAccess" value="always">' +
  1656. '<param name="AllowFullScreen" value="true">' +
  1657. '<param name="AllowFullScreenInteractive" value="true">' +
  1658. '<embed name="' + this.id + '" src="' + swfUrl + '" quality=high pluginspage="//www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" width="' + width + '" height="' + height + '" AllowScriptAccess="always" AllowFullScreen="true" AllowFullScreenInteractive="true" WMode="'+wmode+'" FlashVars="' + flashVar + '">' +
  1659. '</embed>'+
  1660. '</object>';
  1661. //swfobj.registerObject(this._id, "10.1.0");
  1662. },
  1663. _getPlayer: function(id) {
  1664. if (navigator.appName.indexOf("Microsoft") != -1) {
  1665. return document.getElementById(id);
  1666. }else{
  1667. return document[id];
  1668. }
  1669. },
  1670. //增加对 domain,statisticService,videoInfoService,vurl(调整为 source) 的设置支持
  1671. _comboFlashVars: function(){
  1672. var opt = this._options,
  1673. flashVarArr = {
  1674. autoPlay: opt.autoplay ? 1 : 0,
  1675. from: opt.from,
  1676. isInner: 0,
  1677. actRequest: 1,
  1678. //ref: 'share',
  1679. vid: opt.vid,
  1680. domain: opt.domain ? opt.domain : '//tv.taobao.com',
  1681. //statisticService: opt.statisticService ? opt.statisticService : '//log.video.taobao.com/stat/',
  1682. //statisticService: opt.statisticService ? opt.statisticService : '//videocloud.cn-hangzhou.log.aliyuncs.com/logstores/player/track',
  1683. statisticService: opt.statisticService ? opt.statisticService : cfg.logReportTo,
  1684. videoInfoService: opt.videoInfoService?opt.videoInfoService:'/player/json/getBaseVideoInfo.do',
  1685. disablePing: opt.trackLog ? 0 : 1,
  1686. namespace: this.id,
  1687. barMode:opt.barMode,
  1688. //直播状态
  1689. isLive:opt.isLive?1:0,
  1690. //水印
  1691. waterMark:opt.waterMark,
  1692. //直接播放的地址
  1693. vurl:opt.source ? encodeURIComponent(opt.source):"",
  1694. //插件
  1695. plugins:opt.plugins?opt.plugins:"",
  1696. snapShotShow:opt.snapshot ? 1 : 0,
  1697. encryp:opt.encryp ? opt.encryp : "null",
  1698. secret:opt.secret ? opt.secret : "null"
  1699. },
  1700. flashVar = [];
  1701. if (opt.cover) {
  1702. flashVarArr.cover = opt.cover;
  1703. }
  1704. if (opt.extraInfo) {
  1705. flashVarArr.extraInfo = encodeURIComponent(JSON.stringify(opt.extraInfo));
  1706. }
  1707. _.each(flashVarArr, function(k, v) {
  1708. flashVar.push(k + '=' + v);
  1709. });
  1710. return flashVar.join('&');
  1711. },
  1712. /************************ flash调用js的函数 ***********************/
  1713. /**
  1714. * flashPlayer初始化完毕
  1715. */
  1716. flashReady: function() {
  1717. this.flashPlayer = this._getPlayer(this.id);
  1718. this._isReady = true;
  1719. // 传递skin相关
  1720. var skinRes = this._options.skinRes,
  1721. skinLayout = this._options.skinLayout,
  1722. skin;
  1723. // 必须是false或者array
  1724. if (skinLayout !== false && !_.isArray(skinLayout)) {
  1725. throw new Error('PrismPlayer Error: skinLayout should be false or type of array!');
  1726. }
  1727. if (typeof skinRes !== 'string') {
  1728. throw new Error('PrismPlayer Error: skinRes should be string!');
  1729. }
  1730. // 如果是false或者[],隐藏ui组件
  1731. if (skinLayout == false || skinLayout.length === 0) {
  1732. skin = false;
  1733. } else {
  1734. skin = {
  1735. skinRes: skinRes,
  1736. skinLayout: skinLayout
  1737. };
  1738. }
  1739. this.flashPlayer.setPlayerSkin(skin);
  1740. this.trigger('ready');
  1741. // 告知flash播放器页面关闭
  1742. var that = this;
  1743. window.addEventListener('beforeunload', function() {
  1744. try{
  1745. that.flashPlayer.setPlayerCloseStatus();
  1746. }catch(e){
  1747. }
  1748. });
  1749. },
  1750. /**
  1751. * flash调用该函数,轮询js的函数声明是否完成
  1752. */
  1753. jsReady: function() {
  1754. return true;
  1755. },
  1756. uiReady: function() {
  1757. this.trigger('uiReady');
  1758. },
  1759. onPlay: function() {
  1760. this.trigger('play');
  1761. },
  1762. onEnded: function() {
  1763. this.trigger('ended');
  1764. },
  1765. onPause: function() {
  1766. this.trigger('pause');
  1767. },
  1768. //flash弹幕插件初始化完成
  1769. onBulletScreenReady:function(){
  1770. this.trigger('bSReady');
  1771. },
  1772. //flash弹幕发送弹幕消息
  1773. onBulletScreenMsgSend:function(msg){
  1774. this.trigger('bSSendMsg',msg);
  1775. },
  1776. //flash视频开始渲染播放器内逻辑做了单个视频的发送滤重,可以作为canplay的依赖
  1777. onVideoRender:function(time){
  1778. this.trigger('videoRender');
  1779. this.trigger('canplay',{loadtime:time});
  1780. },
  1781. //flash播放器捕捉到错误时调用
  1782. onVideoError:function(type){
  1783. this.trigger('error',{errortype:type});
  1784. },
  1785. //flash catch m3u8 request error and retry
  1786. onM3u8Retry:function(){
  1787. this.trigger('m3u8Retry');
  1788. },
  1789. //flash catch live stream stop
  1790. liveStreamStop:function(){
  1791. this.trigger('liveStreamStop');
  1792. },
  1793. //flash播放器捕捉到缓冲
  1794. onVideoBuffer:function(){
  1795. this.trigger('waiting');
  1796. },
  1797. /**
  1798. * js调用flash函数的基础方法
  1799. */
  1800. _invoke: function() {
  1801. var fnName = arguments[0],
  1802. args = arguments;
  1803. Array.prototype.shift.call(args);
  1804. if (!this.flashPlayer) {
  1805. throw new Error('PrismPlayer Error: flash player is not ready!');
  1806. }
  1807. if (typeof this.flashPlayer[fnName] !== 'function') {
  1808. throw new Error('PrismPlayer Error: function ' + fnName + ' is not found!');
  1809. }
  1810. return this.flashPlayer[fnName].apply(this.flashPlayer, args);
  1811. },
  1812. /* ================ 公共接口 ====================== */
  1813. play: function() {
  1814. this._invoke('playVideo');
  1815. },
  1816. pause: function() {
  1817. this._invoke('pauseVideo');
  1818. },
  1819. stop:function(){
  1820. this._invoke('stopVideo');
  1821. },
  1822. // 秒
  1823. seek: function(time) {
  1824. this._invoke('seekVideo', time);
  1825. },
  1826. getCurrentTime: function() {
  1827. return this._invoke('getCurrentTime');
  1828. },
  1829. getDuration: function() {
  1830. return this._invoke('getDuration');
  1831. },
  1832. mute: function() {
  1833. this.setVolume(0);
  1834. },
  1835. unMute: function() {
  1836. this.setVolume(0.5);
  1837. },
  1838. // 0-1
  1839. getVolume: function() {
  1840. return this._invoke('getVolume');
  1841. },
  1842. // 0-1
  1843. setVolume: function(vol) {
  1844. this._invoke('setVolume', vol);
  1845. },
  1846. //新增接口============================
  1847. //通过id加载视频
  1848. loadByVid: function(vid) {
  1849. this._invoke('loadByVid', vid,false);
  1850. },
  1851. //通过url加载视频
  1852. loadByUrl: function(url, seconds) {
  1853. this._invoke('loadByUrl', url, seconds);
  1854. },
  1855. //销毁 暂停视频,其余的由业务逻辑处理
  1856. dispose: function() {
  1857. this._invoke('pauseVideo');
  1858. },
  1859. //推送弹幕消息,js获取到消息后推送给flash显示
  1860. showBSMsg:function(msg){
  1861. this._invoke('showBSMsg',msg);
  1862. },
  1863. //设置是否启用toast信息提示
  1864. setToastEnabled:function(enabled){
  1865. this._invoke('setToastEnabled',enabled);
  1866. },
  1867. //设置是否显示loading
  1868. setLoadingInvisible:function(){
  1869. this._invoke('setLoadingInvisible');
  1870. },
  1871. //set player size
  1872. setPlayerSize:function(input_w, input_h){
  1873. var that = this;
  1874. this._el.style.width = input_w
  1875. var per_idx = input_h.indexOf("%");
  1876. if (per_idx > 0)
  1877. {
  1878. var screen_height = window.screen.height;
  1879. var per_value = input_h.replace("%", "");
  1880. if(!isNaN(per_value))
  1881. {
  1882. var scale_value = screen_height * 9 * parseInt(per_value) / 1000;
  1883. this._el.style.height = String(scale_value % 2 ? scale_value + 1: scale_value) + "px";
  1884. }
  1885. else
  1886. {
  1887. this._el.style.height = input_h;
  1888. }
  1889. }
  1890. else
  1891. {
  1892. this._el.style.height = input_h;
  1893. }
  1894. console.log(input_w + input_h);
  1895. },
  1896. });
  1897. module.exports = FlashPlayer;
  1898. },{"../config":1,"../lib/data":4,"../lib/object":10,"../ui/component":18}],17:[function(require,module,exports){
  1899. /*
  1900. * 播放器核心类
  1901. *
  1902. */
  1903. var Component = require('../ui/component');
  1904. var _ = require('../lib/object');
  1905. var Dom = require('../lib/dom');
  1906. var Event = require('../lib/event');
  1907. var io = require('../lib/io');
  1908. var UI = require('../ui/exports');
  1909. var Monitor = require('../monitor/monitor');
  1910. var UA = require('../lib/ua');
  1911. var debug_flag = 0;
  1912. var Player = Component.extend({
  1913. init: function (tag, options) {
  1914. this.tag = tag;
  1915. this.loaded = false;
  1916. //调用父类的构造函数
  1917. Component.call(this, this, options);
  1918. //初始化所有插件
  1919. if (options['plugins']) {
  1920. _.each(options['plugins'], function(key, val){
  1921. this[key](val);
  1922. }, this);
  1923. }
  1924. // 如果不使用默认的controls,并且不是iphone,才初始化ui组件
  1925. if (!options['useNativeControls'] /*&& !UA.IS_IPHONE*/) {
  1926. // 将所有可用的ui组件挂载在player下,供初始化组件时索引
  1927. this.UI = UI;
  1928. this.initChildren();
  1929. // 否则设置controls即可
  1930. } else {
  1931. this.tag.setAttribute('controls','controls');
  1932. }
  1933. //监听视频播放器的事件
  1934. this.bindVideoEvent();
  1935. // 如果采用直接传入视频源的方式,则直接播放
  1936. if (this._options.source) {
  1937. // 开始监控
  1938. if (this._options['trackLog']) {
  1939. // 直接传视频源,没有vid和aid,用默认0代替
  1940. this._monitor=new Monitor(this, {video_id: 0, album_id: 0, from: this._options.from});
  1941. }
  1942. // 可以认为此时player init
  1943. this.trigger('init');
  1944. if (debug_flag) {
  1945. console.log('init');
  1946. }
  1947. if (this._options.autoplay) {
  1948. this.getMetaData();
  1949. this.tag.setAttribute('src', this._options.source);
  1950. this.readyTime = new Date().getTime();
  1951. this.loaded = true;
  1952. }
  1953. // 否则,调用接口加载视频资源
  1954. } else if (this._options.vid) {
  1955. this.loadVideoInfo();
  1956. } else {
  1957. // 开始监控
  1958. if (this._options['trackLog']) {
  1959. // 直接传视频源,没有vid和aid,用默认0代替
  1960. this._monitor=new Monitor(this, {video_id: 0, album_id: 0, from: this._options.from});
  1961. }
  1962. // 可以认为此时player init
  1963. this.trigger('init');
  1964. if (debug_flag) {
  1965. console.log('init');
  1966. }
  1967. }
  1968. if (this._options.extraInfo) {
  1969. var dict = eval(this._options.extraInfo);
  1970. if (dict.liveRetry)
  1971. this._options.liveRetry = dict.liveRetry;
  1972. }
  1973. //要想拿到video的元数据,必须等到readyState > 0
  1974. this.on('readyState',function(){
  1975. //是否出现控制面板
  1976. //this.setControls();
  1977. this.trigger('ready');
  1978. if (debug_flag) {
  1979. console.log('ready');
  1980. //alert('ready');
  1981. }
  1982. });
  1983. }
  1984. });
  1985. /**
  1986. * 重写component的initChildren,
  1987. * player的children通过options.skin传入
  1988. */
  1989. Player.prototype.initChildren = function() {
  1990. var opt = this.options(),
  1991. skin = opt.skinLayout;
  1992. // 必须是false或者array
  1993. if (skin !== false && !_.isArray(skin)) {
  1994. throw new Error('PrismPlayer Error: skinLayout should be false or type of array!');
  1995. }
  1996. // 如果是false或者[],隐藏ui组件
  1997. if (skin !== false && skin.length !== 0) {
  1998. this.options({
  1999. children: skin
  2000. });
  2001. Component.prototype.initChildren.call(this);
  2002. }
  2003. // 所有ui组件被正式添加到dom树后触发
  2004. this.trigger('uiH5Ready');
  2005. if (debug_flag) {
  2006. console.log('uiH5ready');
  2007. }
  2008. },
  2009. Player.prototype.createEl = function() {
  2010. if(this.tag.tagName !== 'VIDEO'){
  2011. this._el = this.tag;
  2012. this.tag = Component.prototype.createEl.call(this, 'video');
  2013. //如果设置了 inline 播放
  2014. if (this._options.playsinline) {
  2015. this.tag.setAttribute('webkit-playsinline','');
  2016. };
  2017. }
  2018. var el = this._el,
  2019. tag = this.tag,
  2020. that = this;
  2021. //该video已经被初始化为播放器
  2022. tag['player'] = this;
  2023. //把video标签上的属性转移到外围容器上
  2024. var attrs = Dom.getElementAttributes(tag);
  2025. _.each(attrs,function(attr){
  2026. el.setAttribute(attr,attrs[attr]);
  2027. });
  2028. //设置video标签属性
  2029. this.setVideoAttrs();
  2030. // 把video标签包裹在el这个容器中
  2031. if (tag.parentNode) {
  2032. tag.parentNode.insertBefore(el, tag);
  2033. }
  2034. Dom.insertFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup.*''
  2035. // 为了屏蔽各个浏览器下video标签的默认样式,需要在其上加一层遮罩
  2036. this.cover = Dom.createEl('div');
  2037. Dom.addClass(this.cover, 'prism-cover');
  2038. el.appendChild(this.cover);
  2039. if (this.options().cover) {
  2040. this.cover.style.backgroundImage = 'url(' + this.options().cover + ')';
  2041. }
  2042. if (!UA.IS_IOS) {
  2043. /*
  2044. this.cover = Dom.createEl('div');
  2045. Dom.addClass(this.cover, 'prism-cover');
  2046. el.appendChild(this.cover);
  2047. if (this.options().cover) {
  2048. this.cover.style.backgroundImage = 'url(' + this.options().cover + ')';
  2049. }
  2050. */
  2051. // ios下用遮罩的方式触发播放有问题,只能使用display:none的方式
  2052. } else {
  2053. Dom.css(tag, 'display', 'none');
  2054. }
  2055. return el;
  2056. };
  2057. Player.prototype.setVideoAttrs = function(){
  2058. var preload = this._options.preload,
  2059. autoplay = this._options.autoplay;
  2060. this.tag.style.width = '100%';
  2061. this.tag.style.height = '100%';
  2062. if (preload) {
  2063. this.tag.setAttribute('preload','preload');
  2064. }
  2065. if (autoplay) {
  2066. this.tag.setAttribute('autoplay','autoplay');
  2067. }
  2068. }
  2069. /**
  2070. * sleep function
  2071. */
  2072. function sleep(d){
  2073. for(var t = Date.now();Date.now() - t <= d;);
  2074. }
  2075. /**
  2076. * player的id直接返回组件的id
  2077. */
  2078. Player.prototype.id = function() {
  2079. return this.el().id;
  2080. };
  2081. Player.prototype.renderUI = function() {};
  2082. Player.prototype.bindVideoEvent = function(){
  2083. var tag = this.tag,
  2084. that = this;
  2085. //(1)开始load数据
  2086. Event.on(tag, 'loadstart', function(e){
  2087. that.trigger('loadstart');
  2088. if (debug_flag) {
  2089. console.log('loadstart');
  2090. //alert('loadstart');
  2091. }
  2092. });
  2093. //(2)加载视频时长
  2094. Event.on(tag, 'durationchange', function(e){
  2095. that.trigger('durationchange');
  2096. if (debug_flag) {
  2097. console.log('durationchange');
  2098. //alert('durationchange');
  2099. }
  2100. });
  2101. //(3)成功获取资源长度
  2102. Event.on(tag, 'loadedmetadata', function(e){
  2103. that.trigger('loadedmetadata');
  2104. if (debug_flag) {
  2105. console.log('loadedmetadata');
  2106. //alert('loadedmetadata');
  2107. }
  2108. });
  2109. //(4)已加载当前帧,但无足够数据播放
  2110. Event.on(tag, 'loadeddata', function(e){
  2111. that.trigger('loadeddata');
  2112. if (debug_flag) {
  2113. console.log('loadeddata');
  2114. //alert('loadeddata');
  2115. }
  2116. });
  2117. //(5)客户端正在请求数据
  2118. Event.on(tag, 'progress', function(e){
  2119. that.trigger('progress');
  2120. if (debug_flag) {
  2121. console.log('progress');
  2122. //alert('progress');
  2123. }
  2124. });
  2125. //(6)可以播放数据
  2126. Event.on(tag, 'canplay', function(e){
  2127. var time=(new Date().getTime())-that.readyTime;
  2128. that.trigger('canplay',{loadtime:time});
  2129. if (debug_flag) {
  2130. console.log('canplay');
  2131. //alert('canplay');
  2132. }
  2133. });
  2134. //(7)可以无缓冲播放数据
  2135. Event.on(tag, 'canplaythrough', function(e){
  2136. if (that.cover/* && !UA.IS_IOS*/) {
  2137. Dom.css(that.cover, 'display', 'none');
  2138. delete that.cover;
  2139. }/* else */if (tag.style.display === 'none' && UA.IS_IOS) {
  2140. setTimeout(function() {
  2141. Dom.css(tag, 'display', 'block');
  2142. }, 100);
  2143. }
  2144. that.trigger('canplaythrough');
  2145. if (debug_flag) {
  2146. console.log('canplaythrough');
  2147. }
  2148. });
  2149. //开始播放触发事件
  2150. Event.on(tag, 'play', function(e){
  2151. that.trigger('play');
  2152. if (debug_flag) {
  2153. console.log('play');
  2154. }
  2155. });
  2156. //none
  2157. Event.on(tag,'play',function(e){
  2158. that.trigger('videoRender');
  2159. if (debug_flag) {
  2160. console.log('videoRender');
  2161. }
  2162. });
  2163. //暂停触发事件
  2164. Event.on(tag, 'pause', function(e){
  2165. that.trigger('pause');
  2166. if (debug_flag) {
  2167. console.log('pause');
  2168. }
  2169. });
  2170. //结束
  2171. Event.on(tag, 'ended', function(e){
  2172. that.trigger('ended');
  2173. if (debug_flag) {
  2174. console.log('ended');
  2175. }
  2176. });
  2177. //客户端尝试获取数据 none
  2178. Event.on(tag, 'stalled', function(e){
  2179. that.trigger('stalled');
  2180. if (debug_flag) {
  2181. console.log('stalled');
  2182. }
  2183. });
  2184. //缓冲等待数据
  2185. Event.on(tag, 'waiting', function(e){
  2186. that.trigger('waiting');
  2187. if (debug_flag) {
  2188. console.log('waiting');
  2189. }
  2190. });
  2191. //播放中
  2192. Event.on(tag, 'playing', function(e){
  2193. that.trigger('playing');
  2194. if (debug_flag) {
  2195. console.log('playing');
  2196. }
  2197. });
  2198. Event.on(tag, 'error', function(e){
  2199. console.log('error');
  2200. //console.log(e);
  2201. if (that._options.isLive)
  2202. {
  2203. if(that._options.liveRetry)
  2204. {
  2205. sleep(2000);
  2206. that.tag.load(that._options.source);
  2207. that.tag.play();
  2208. }
  2209. else
  2210. {
  2211. that.trigger('error');
  2212. }
  2213. that.trigger('liveStreamStop');
  2214. }
  2215. else
  2216. {
  2217. that.trigger('error');
  2218. }
  2219. });
  2220. //not exist now
  2221. Event.on(tag, 'onM3u8Retry', function(e){
  2222. that.trigger('m3u8Retry');
  2223. if (debug_flag) {
  2224. console.log('m3u8Retry');
  2225. }
  2226. });
  2227. //not exist now
  2228. Event.on(tag, 'liveStreamStop', function(e){
  2229. that.trigger('liveStreamStop');
  2230. if (debug_flag) {
  2231. console.log('liveStreamStop');
  2232. }
  2233. });
  2234. //寻找中
  2235. Event.on(tag, 'seeking', function(e){
  2236. that.trigger('seeking');
  2237. if (debug_flag) {
  2238. console.log('seeking');
  2239. }
  2240. });
  2241. //寻找完毕
  2242. Event.on(tag, 'seeked', function(e){
  2243. that.trigger('seeked');
  2244. if (debug_flag) {
  2245. console.log('seeked');
  2246. }
  2247. });
  2248. //播放速率改变
  2249. Event.on(tag, 'ratechange', function(e){
  2250. that.trigger('ratechange');
  2251. if (debug_flag) {
  2252. console.log('ratechange');
  2253. }
  2254. });
  2255. //播放过程触发的事件
  2256. Event.on(tag,'timeupdate',function(e){
  2257. //var currentTime = e.target.currentTime;
  2258. //that.currentTime(currentTime);
  2259. that.trigger('timeupdate');
  2260. if (debug_flag) {
  2261. console.log('timeupdate');
  2262. }
  2263. });
  2264. //全屏修改
  2265. Event.on(tag, 'webkitfullscreenchange', function(e){
  2266. that.trigger('fullscreenchange');
  2267. if (debug_flag) {
  2268. console.log('fullscreenchange');
  2269. }
  2270. });
  2271. this.on('requestFullScreen', function() {
  2272. Dom.addClass(that.el(), 'prism-fullscreen');
  2273. if (debug_flag) {
  2274. console.log('request-fullscreen');
  2275. }
  2276. });
  2277. this.on('cancelFullScreen', function() {
  2278. Dom.removeClass(that.el(), 'prism-fullscreen');
  2279. if (debug_flag) {
  2280. console.log('cancel-fullscreen');
  2281. }
  2282. });
  2283. //may not used
  2284. Event.on(tag,'suspend',function(e){
  2285. that.trigger('suspend');
  2286. if (debug_flag) {
  2287. console.log('sudpend');
  2288. }
  2289. });
  2290. Event.on(tag,'abort',function(e){
  2291. that.trigger('abort');
  2292. if (debug_flag) {
  2293. console.log('abort');
  2294. }
  2295. });
  2296. Event.on(tag,'volumechange',function(e){
  2297. that.trigger('volumechange');
  2298. if (debug_flag) {
  2299. console.log('volumechange');
  2300. }
  2301. });
  2302. Event.on(tag,'drag',function(e){
  2303. that.trigger('drag');
  2304. if (debug_flag) {
  2305. console.log('drag');
  2306. }
  2307. });
  2308. Event.on(tag,'dragstart',function(e){
  2309. that.trigger('dragstart');
  2310. if (debug_flag) {
  2311. console.log('dragstart');
  2312. //alert('dragstart');
  2313. }
  2314. });
  2315. Event.on(tag,'dragover',function(e){
  2316. that.trigger('dragover');
  2317. //console.log('dragover');
  2318. //alert('dragover');
  2319. });
  2320. Event.on(tag,'dragenter',function(e){
  2321. that.trigger('dragenter');
  2322. //console.log('dragenter');
  2323. //alert('dragenter');
  2324. });
  2325. Event.on(tag,'dragleave',function(e){
  2326. that.trigger('dragleave');
  2327. //console.log('dragleave');
  2328. //alert('dragleave');
  2329. });
  2330. Event.on(tag,'ondrag',function(e){
  2331. that.trigger('ondrag');
  2332. //console.log('ondrag');
  2333. //alert('ondrag');
  2334. });
  2335. Event.on(tag,'ondragstart',function(e){
  2336. that.trigger('ondragstart');
  2337. //console.log('ondragstart');
  2338. //alert('ondragstart');
  2339. });
  2340. Event.on(tag,'ondragover',function(e){
  2341. that.trigger('ondragover');
  2342. //console.log('ondragover');
  2343. //alert('ondragover');
  2344. });
  2345. Event.on(tag,'ondragenter',function(e){
  2346. that.trigger('ondragenter');
  2347. //console.log('ondragenter');
  2348. //alert('ondragenter');
  2349. });
  2350. Event.on(tag,'ondragleave',function(e){
  2351. that.trigger('ondragleave');
  2352. //console.log('ondragleave');
  2353. //alert('ondragleave');
  2354. });
  2355. Event.on(tag,'drop',function(e){
  2356. that.trigger('drop');
  2357. //console.log('drop');
  2358. //alert('drop');
  2359. });
  2360. Event.on(tag,'dragend',function(e){
  2361. that.trigger('dragend');
  2362. //console.log('dragend');
  2363. //alert('dragend');
  2364. });
  2365. Event.on(tag,'onscroll',function(e){
  2366. that.trigger('onscroll');
  2367. //console.log('onscroll');
  2368. //alert('onscroll');
  2369. });
  2370. }
  2371. /**
  2372. * 异步获取videoinfo,成功后触发readyState的检测hack,
  2373. * 因为有很多ui组件的ui更新需要依赖于metadata(时长、buffered等)
  2374. */
  2375. Player.prototype.loadVideoInfo = function() {
  2376. var vid = this._options.vid,
  2377. that = this;
  2378. if (!vid) {
  2379. throw new Error('PrismPlayer Error: vid should not be null!');
  2380. }
  2381. // tv.taobao.com
  2382. io.jsonp('//tv.taobao.com/player/json/getBaseVideoInfo.do?vid=' + vid + '&playerType=3', function(data) {
  2383. // applewatch 和 new iphone的临时修改,由于这个活动访问量较大,接口请求临时走cdn
  2384. //io.jsonp('//www.taobao.com/go/rgn/tv/ajax/applewatch-media.php?vid=' + vid + '&playerType=3', function(data) {
  2385. if (data.status === 1 && data.data.source) {
  2386. var src,
  2387. maxDef = -1;
  2388. _.each(data.data.source, function(k, v) {
  2389. var def = +k.substring(1);
  2390. if (def > maxDef) maxDef = def;
  2391. });
  2392. src = data.data.source['v' + maxDef];
  2393. src = _.unescape(src)/*.replace(/n\.videotest\.alikunlun\.com/g, 'd.tv.taobao.com')*/;
  2394. that._options.source = src;
  2395. // 开始监控
  2396. if (that._options['trackLog']) {
  2397. that._monitor=new Monitor(that, {video_id: vid, album_id: data.data.baseInfo.aid, from: that._options.from});
  2398. }
  2399. // 可以认为此时player init
  2400. that.trigger('init');
  2401. if (debug_flag) {
  2402. console.log('init');
  2403. }
  2404. if (that._options.autoplay) {
  2405. that.getMetaData();
  2406. that.tag.setAttribute('src', that._options.source);
  2407. that.readyTime = new Date().getTime();
  2408. that.loaded = true;
  2409. }
  2410. } else {
  2411. throw new Error('PrismPlayer Error: #vid:' + vid + ' cannot find video resource!');
  2412. }
  2413. }, function() {
  2414. throw new Error('PrismPlayer Error: network error!');
  2415. });
  2416. };
  2417. Player.prototype.setControls = function(){
  2418. var options = this.options();
  2419. //如果指定使用系统默认的控制面板
  2420. if(options.useNativeControls){
  2421. //alert("native_control");
  2422. this.tag.setAttribute('controls','controls');
  2423. }else{
  2424. //否则使用我们自定义的控制面板
  2425. // TODO
  2426. //alert("define_control");
  2427. if(typeof options.controls === 'object'){
  2428. //options.controls为controbar的配置项
  2429. var controlBar = this._initControlBar(options.controls);
  2430. this.addChild(controlBar);
  2431. }
  2432. }
  2433. }
  2434. //
  2435. Player.prototype._initControlBar = function(options){
  2436. var controlBar = new ControlBar(this,options);
  2437. return controlBar;
  2438. }
  2439. /**
  2440. * 获取视频元数据信息
  2441. */
  2442. Player.prototype.getMetaData = function(){
  2443. var that = this,
  2444. timer = null,
  2445. video = this.tag;
  2446. timer = window.setInterval(function(t){
  2447. if (video.readyState > 0) {
  2448. var vid_duration = Math.round(video.duration);
  2449. that.tag.duration = vid_duration;
  2450. //that.readyTime = new Date().getTime() - that.readyTime;
  2451. that.trigger('readyState');
  2452. if (debug_flag) {
  2453. console.log('readystate');
  2454. }
  2455. clearInterval(timer);
  2456. }
  2457. }, 100);
  2458. };
  2459. Player.prototype.getReadyTime = function() {
  2460. return this.readyTime;
  2461. };
  2462. Player.prototype.readyState = function() {
  2463. return this.tag.readyState;
  2464. };
  2465. Player.prototype.getError = function() {
  2466. return this.tag.error;
  2467. };
  2468. /* 标准化播放器api
  2469. ============================================================================= */
  2470. //开始播放视频
  2471. Player.prototype.play = function(){
  2472. var that = this;
  2473. if (!this._options.autoplay && !this.loaded) {
  2474. this.getMetaData();
  2475. this.tag.setAttribute('src', this._options.source);
  2476. this.readyTime = new Date().getTime();
  2477. this.loaded = true;
  2478. }
  2479. this.tag.play();
  2480. if (debug_flag) {
  2481. //alert('click_play');
  2482. }
  2483. return this;
  2484. }
  2485. //暂停视频
  2486. Player.prototype.pause = function(){
  2487. this.tag.pause();
  2488. return this;
  2489. }
  2490. //停止视频
  2491. Player.prototype.stop = function(){
  2492. this.tag.setAttribute('src',null);
  2493. return this;
  2494. }
  2495. Player.prototype.paused = function(){
  2496. // The initial state of paused should be true (in Safari it's actually false)
  2497. return this.tag.paused === false ? false : true;
  2498. };
  2499. //获取视频总时长
  2500. Player.prototype.getDuration = function(){
  2501. var totalDuration = this.tag.duration;
  2502. return totalDuration;
  2503. }
  2504. //设置或者获取当前播放时间
  2505. Player.prototype.getCurrentTime = function(){
  2506. var currentTime = this.tag.currentTime;
  2507. return currentTime;
  2508. }
  2509. Player.prototype.seek = function(time){
  2510. if (time === this.tag.duration) time--;
  2511. try {
  2512. this.tag.currentTime = time;
  2513. } catch(e) {
  2514. console.log(e);
  2515. }
  2516. return this;
  2517. }
  2518. //通过id加载视频
  2519. Player.prototype.loadByVid=function(vid) {
  2520. this._options.vid=vid;
  2521. var that = this;
  2522. if (!vid) {
  2523. throw new Error('PrismPlayer Error: vid should not be null!');
  2524. }
  2525. // tv.taobao.com
  2526. io.jsonp('//tv.taobao.com/player/json/getBaseVideoInfo.do?vid=' + vid + '&playerType=3', function(data) {
  2527. // applewatch 和 new iphone的临时修改,由于这个活动访问量较大,接口请求临时走cdn
  2528. //io.jsonp('//www.taobao.com/go/rgn/tv/ajax/applewatch-media.php?vid=' + vid + '&playerType=3', function(data) {
  2529. if (data.status === 1 && data.data.source) {
  2530. var src,
  2531. maxDef = -1;
  2532. _.each(data.data.source, function(k, v) {
  2533. var def = +k.substring(1);
  2534. if (def > maxDef) maxDef = def;
  2535. });
  2536. src = data.data.source['v' + maxDef];
  2537. src = _.unescape(src)/*.replace(/n\.videotest\.alikunlun\.com/g, 'd.tv.taobao.com')*/;
  2538. that._options.source = src;
  2539. // 开始监控
  2540. if (that._options['trackLog']) {
  2541. if (that._monitor) {
  2542. that._monitor.updateVideoInfo({video_id: vid, album_id: data.data.baseInfo.aid, from: that._options.from});
  2543. }else{
  2544. that._monitor=new Monitor(that, {video_id: vid, album_id: data.data.baseInfo.aid, from: that._options.from});
  2545. };
  2546. }
  2547. that._options.autoplay=true;
  2548. // 可以认为此时player init
  2549. if (!that.loaded) {
  2550. that.trigger('init');
  2551. if (debug_flag) {
  2552. console.log('init');
  2553. }
  2554. };
  2555. that.getMetaData();
  2556. that.tag.setAttribute('src', that._options.source);
  2557. that.readyTime = new Date().getTime();
  2558. that.loaded = true;
  2559. that.tag.play();
  2560. } else {
  2561. throw new Error('PrismPlayer Error: #vid:' + vid + ' cannot find video resource!');
  2562. }
  2563. }, function() {
  2564. throw new Error('PrismPlayer Error: network error!');
  2565. });
  2566. }
  2567. //通过url加载视频
  2568. Player.prototype.loadByUrl=function(url, seconds) {
  2569. this._options.vid=0;
  2570. this._options.source=url;
  2571. this._options.autoplay=true;
  2572. // 开始监控
  2573. if (this._options['trackLog']) {
  2574. if (this._monitor) {
  2575. this._monitor.updateVideoInfo({video_id: 0, album_id: 0, from: this._options.from});
  2576. }else{
  2577. this._monitor=new Monitor(this,{video_id: 0, album_id: 0, from: this._options.from});
  2578. };
  2579. }
  2580. // 可以认为此时player init
  2581. if (!this.loaded) {
  2582. this.trigger('init');
  2583. if (debug_flag) {
  2584. console.log('init');
  2585. }
  2586. };
  2587. this.getMetaData();
  2588. this.tag.setAttribute('src', this._options.source);
  2589. this.readyTime = new Date().getTime();
  2590. this.loaded = true;
  2591. this.tag.play();
  2592. if (seconds && !isNaN(seconds)) {
  2593. this.seek(seconds);
  2594. }
  2595. }
  2596. //播放器销毁方法在清除节点前调用
  2597. Player.prototype.dispose=function(){
  2598. this.tag.pause();
  2599. //remove events
  2600. var tag = this.tag,
  2601. that = this;
  2602. //播放过程触发的事件
  2603. Event.off(tag,'timeupdate');
  2604. //开始播放触发事件
  2605. Event.off(tag, 'play');
  2606. //暂停触发事件
  2607. Event.off(tag, 'pause');
  2608. Event.off(tag, 'canplay');
  2609. Event.off(tag, 'waiting');
  2610. Event.off(tag, 'playing');
  2611. Event.off(tag, 'ended');
  2612. Event.off(tag, 'error');
  2613. Event.off(tag, 'durationchange');
  2614. Event.off(tag, 'loadedmetadata');
  2615. Event.off(tag, 'loadeddata');
  2616. Event.off(tag, 'progress');
  2617. Event.off(tag, 'canplaythrough');
  2618. Event.off(tag, 'webkitfullscreenchange');
  2619. this.tag=null;
  2620. this._options=null;
  2621. if (this._monitor) {
  2622. this._monitor.removeEvent();
  2623. this._monitor=null;
  2624. };
  2625. }
  2626. //设置静音或者获取是否静音
  2627. Player.prototype.mute = function(){
  2628. this.tag.muted = true;
  2629. return this;
  2630. }
  2631. Player.prototype.unMute = function(){
  2632. this.tag.muted = false;
  2633. return this;
  2634. }
  2635. Player.prototype.muted = function() {
  2636. return this.tag.muted;
  2637. };
  2638. //设置或者获取音量
  2639. Player.prototype.getVolume = function(){
  2640. return this.tag.volume;
  2641. }
  2642. //获取配置
  2643. Player.prototype.getOptions=function(){
  2644. return this._options;
  2645. }
  2646. /*
  2647. 0-1区间
  2648. */
  2649. Player.prototype.setVolume = function(volume){
  2650. this.tag.volume = volume;
  2651. }
  2652. //隐藏进度条控制
  2653. Player.prototype.hideProgress = function(){
  2654. var that = this;
  2655. that.trigger('hideProgress');
  2656. console.log("send hide flag");
  2657. }
  2658. //取消隐藏进度条控制
  2659. Player.prototype.cancelHideProgress = function(){
  2660. var that = this;
  2661. that.trigger('cancelHideProgress');
  2662. console.log("send cancel flag");
  2663. }
  2664. //set player size when play
  2665. Player.prototype.setPlayerSize = function(input_w, input_h){
  2666. var that = this;
  2667. this._el.style.width = input_w
  2668. if (input_h)
  2669. {
  2670. var per_idx = input_h.indexOf("%");
  2671. if (per_idx > 0)
  2672. {
  2673. var screen_height = window.screen.height;
  2674. var per_value = input_h.replace("%", "");
  2675. if(!isNaN(per_value))
  2676. {
  2677. var scale_value = screen_height * 9 * parseInt(per_value) / 1000;
  2678. this._el.style.height = String(scale_value % 2 ? scale_value + 1: scale_value) + "px";
  2679. }
  2680. else
  2681. {
  2682. this._el.style.height = input_h;
  2683. }
  2684. }
  2685. else
  2686. {
  2687. this._el.style.height = input_h;
  2688. }
  2689. }
  2690. }
  2691. /*
  2692. //no full sreen function call
  2693. var fullScreenNoSupportCall = (function() {
  2694. var docHtml = document.documentElement;
  2695. var docBody = document.body;
  2696. var videobox = document.getElementById('videobox');
  2697. var cssText = 'width:100%;height:100%;overflow:hidden;';
  2698. docHtml.style.cssText = cssText;
  2699. // docBody.style.cssText = cssText;
  2700. videobox.style.cssText = cssText+';'+'margin:0px;padding:0px;';
  2701. document.IsFullScreen = true;
  2702. })()
  2703. //no full sreen function exit
  2704. var fullScreenNoSupportExit = (function() {
  2705. var docHtml = document.documentElement;
  2706. var docBody = document.body;
  2707. var videobox = document.getElementById('videobox');
  2708. docHtml.style.cssText = "";
  2709. // docBody.style.cssText = "";
  2710. videobox.style.cssText = "";
  2711. document.IsFullScreen = false;
  2712. })()
  2713. */
  2714. // 检测fullscreen的支持情况,即时函数
  2715. var __supportFullscreen = (function() {
  2716. var prefix, requestFS, div;
  2717. div = Dom.createEl('div');
  2718. requestFS = {};
  2719. var apiMap = [
  2720. // Spec: https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html
  2721. [
  2722. 'requestFullscreen',
  2723. 'exitFullscreen',
  2724. 'fullscreenElement',
  2725. 'fullscreenEnabled',
  2726. 'fullscreenchange',
  2727. 'fullscreenerror',
  2728. 'fullScreen'
  2729. ],
  2730. // WebKit
  2731. [
  2732. 'webkitRequestFullscreen',
  2733. 'webkitExitFullscreen',
  2734. 'webkitFullscreenElement',
  2735. 'webkitFullscreenEnabled',
  2736. 'webkitfullscreenchange',
  2737. 'webkitfullscreenerror',
  2738. 'webkitfullScreen'
  2739. ],
  2740. // Old WebKit(Safari 5.1)
  2741. [
  2742. 'webkitRequestFullScreen',
  2743. 'webkitCancelFullScreen',
  2744. 'webkitCurrentFullScreenElement',
  2745. 'webkitFullscreenEnabled',
  2746. 'webkitfullscreenchange',
  2747. 'webkitfullscreenerror',
  2748. 'webkitIsFullScreen'
  2749. ],
  2750. // // safari iOS
  2751. // [
  2752. // 'webkitEnterFullscreen',
  2753. // 'webkitExitFullscreen',
  2754. // 'webkitCurrentFullScreenElement',
  2755. // 'webkitCancelFullScreen',
  2756. // 'webkitfullscreenchange',
  2757. // 'webkitfullscreenerror',
  2758. // 'webkitDisplayingFullscreen'
  2759. // ],
  2760. // Mozilla
  2761. [
  2762. 'mozRequestFullScreen',
  2763. 'mozCancelFullScreen',
  2764. 'mozFullScreenElement',
  2765. 'mozFullScreenEnabled',
  2766. 'mozfullscreenchange',
  2767. 'mozfullscreenerror',
  2768. 'mozfullScreen'
  2769. ],
  2770. // Microsoft
  2771. [
  2772. 'msRequestFullscreen',
  2773. 'msExitFullscreen',
  2774. 'msFullscreenElement',
  2775. 'msFullscreenEnabled',
  2776. 'MSFullscreenChange',
  2777. 'MSFullscreenError',
  2778. 'MSFullScreen'
  2779. ]
  2780. ];
  2781. if (UA.IS_IOS) {
  2782. //IOS 特殊处理
  2783. requestFS.requestFn="webkitEnterFullscreen";
  2784. requestFS.cancelFn="webkitExitFullscreen";
  2785. requestFS.eventName="webkitfullscreenchange";
  2786. requestFS.isFullScreen ="webkitDisplayingFullscreen";
  2787. }else{
  2788. var l=5;
  2789. for (var i = 0; i < l; i++) {
  2790. // check for exitFullscreen function
  2791. if (apiMap[i][1] in document) {
  2792. requestFS.requestFn=apiMap[i][0];
  2793. requestFS.cancelFn=apiMap[i][1];
  2794. requestFS.eventName=apiMap[i][4];
  2795. requestFS.isFullScreen =apiMap[i][6];
  2796. break;
  2797. }
  2798. }
  2799. //modify if has write fun
  2800. //full screen
  2801. if ( 'requestFullscreen' in document) {
  2802. requestFS.requestFn='requestFullscreen';
  2803. } else if ( 'webkitRequestFullscreen' in document ) {
  2804. requestFS.requestFn='webkitRequestFullscreen';
  2805. } else if ( 'webkitRequestFullScreen' in document ) {
  2806. requestFS.requestFn='webkitRequestFullScreen';
  2807. } else if ( 'webkitEnterFullscreen' in document ) {
  2808. requestFS.requestFn='webkitEnterFullscreen';
  2809. } else if ( 'mozRequestFullScreen' in document ) {
  2810. requestFS.requestFn='mozRequestFullScreen';
  2811. } else if ( 'msRequestFullscreen' in document ) {
  2812. requestFS.requestFn='msRequestFullscreen';
  2813. }
  2814. //full screen change
  2815. if ( 'fullscreenchange' in document) {
  2816. requestFS.eventName='fullscreenchange';
  2817. } else if ( 'webkitfullscreenchange' in document ) {
  2818. requestFS.eventName='webkitfullscreenchange';
  2819. } else if ( 'webkitfullscreenchange' in document ) {
  2820. requestFS.eventName='webkitfullscreenchange';
  2821. } else if ( 'webkitfullscreenchange' in document ) {
  2822. requestFS.eventName='webkitfullscreenchange';
  2823. } else if ( 'mozfullscreenchange' in document ) {
  2824. requestFS.eventName='mozfullscreenchange';
  2825. } else if ( 'MSFullscreenChange' in document ) {
  2826. requestFS.eventName='MSFullscreenChange';
  2827. }
  2828. //full screen status
  2829. if ( 'fullScreen' in document) {
  2830. requestFS.isFullScreen='fullScreen';
  2831. } else if ( 'webkitfullScreen' in document ) {
  2832. requestFS.isFullScreen='webkitfullScreen';
  2833. } else if ( 'webkitIsFullScreen' in document ) {
  2834. requestFS.isFullScreen='webkitIsFullScreen';
  2835. } else if ( 'webkitDisplayingFullscreen' in document ) {
  2836. requestFS.isFullScreen='webkitDisplayingFullscreen';
  2837. } else if ( 'mozfullScreen' in document ) {
  2838. requestFS.isFullScreen='mozfullScreen';
  2839. } else if ( 'MSFullScreen' in document ) {
  2840. requestFS.isFullScreen='MSFullScreen';
  2841. }
  2842. };
  2843. // 如果浏览器实现了W3C标准的定义
  2844. /*if (div.cancelFullscreen !== undefined) {
  2845. requestFS.requestFn = 'requestFullscreen';
  2846. requestFS.cancelFn = 'cancelFullscreen';
  2847. requestFS.eventName = 'fullscreenchange';
  2848. requestFS.isFullScreen = 'fullScreen';
  2849. // 如果是webkit和mozilla内核,调用全屏接口时需要带前缀
  2850. } else {
  2851. if (document.mozCancelFullScreen) {
  2852. prefix = 'moz';
  2853. requestFS.isFullScreen = prefix + 'FullScreen';
  2854. } else {
  2855. prefix = 'webkit';
  2856. requestFS.isFullScreen = prefix + 'IsFullScreen';
  2857. }
  2858. if (div[prefix + 'RequestFullScreen']) {
  2859. requestFS.requestFn = prefix + 'RequestFullScreen';
  2860. requestFS.cancelFn = prefix + 'CancelFullScreen';
  2861. }else if( div[prefix + 'EnterFullScreen']){
  2862. requestFS.requestFn=prefix + 'EnterFullScreen';
  2863. if(div[prefix + 'CancelFullScreen']){
  2864. requestFS.cancelFn = prefix + 'CancelFullScreen';
  2865. }else if(div[prefix + 'ExitFullscreen']){
  2866. requestFS.cancelFn = prefix + 'ExitFullscreen';
  2867. }
  2868. }
  2869. requestFS.eventName = prefix + 'fullscreenchange';
  2870. }*/
  2871. if (requestFS.requestFn) {
  2872. return requestFS;
  2873. }
  2874. // 如果浏览器不支持全屏接口,返回null
  2875. return null;
  2876. })();
  2877. // 注意,即时函数
  2878. /**
  2879. * 不支持fullscreenAPI时的全屏模拟
  2880. *
  2881. * @method _enterFullWindow
  2882. * @private
  2883. */
  2884. Player.prototype._enterFullWindow = function() {
  2885. var that = this;
  2886. this.isFullWindow = true;
  2887. this.docOrigOverflow = document.documentElement.style.overflow;
  2888. document.documentElement.style.overflow = 'hidden';
  2889. Dom.addClass(document.getElementsByTagName('body')[0], 'prism-full-window');
  2890. //this.trigger('enterfullwindow');
  2891. };
  2892. /**
  2893. * 不支持fullscreenAPI时的取消全屏模拟
  2894. *
  2895. * @method _exitFullWindow
  2896. * @private
  2897. */
  2898. Player.prototype._exitFullWindow = function() {
  2899. this.isFullWindow = false;
  2900. document.documentElement.style.overflow = this.docOrigOverflow;
  2901. Dom.removeClass(document.getElementsByTagName('body')[0], 'prism-full-window');
  2902. //this.trigger('exitfullwindow');
  2903. };
  2904. /**
  2905. * 设置全屏
  2906. *
  2907. * @method requestFullScreen
  2908. */
  2909. Player.prototype.requestFullScreen = function() {
  2910. //alert("call_full");
  2911. var requestFullScreen = __supportFullscreen,
  2912. conTag = this.el(),
  2913. that = this;
  2914. if (UA.IS_IOS) {
  2915. conTag=this.tag;
  2916. conTag[requestFullScreen.requestFn]();
  2917. return this;
  2918. };
  2919. this.isFullScreen = true;
  2920. // 如果浏览器支持全屏接口
  2921. if (requestFullScreen) {
  2922. Event.on(document, requestFullScreen.eventName, function(e) {
  2923. that.isFullScreen = document[requestFullScreen.isFullScreen];
  2924. if (that.isFullScreen === true) {
  2925. Event.off(document, requestFullScreen.eventName);
  2926. }
  2927. //alert("open status:" + that.isFullScreen);
  2928. that.trigger('requestFullScreen');
  2929. });
  2930. conTag[requestFullScreen.requestFn]();
  2931. // 如果不支持全屏接口,则模拟实现
  2932. } else {
  2933. this._enterFullWindow();
  2934. this.trigger('requestFullScreen');
  2935. }
  2936. return this;
  2937. };
  2938. /**
  2939. * 取消全屏
  2940. *
  2941. * @method cancelFullScreen
  2942. */
  2943. Player.prototype.cancelFullScreen = function() {
  2944. //alert("quit_full");
  2945. var requestFullScreen = __supportFullscreen,
  2946. that = this;
  2947. this.isFullScreen = false;
  2948. if (requestFullScreen) {
  2949. Event.on(document, requestFullScreen.eventName, function(e) {
  2950. that.isFullScreen = document[requestFullScreen.isFullScreen];
  2951. if (that.isFullScreen === false) {
  2952. Event.off(document, requestFullScreen.eventName);
  2953. }
  2954. //alert("close status:" + that.isFullScreen);
  2955. that.trigger('cancelFullScreen');
  2956. });
  2957. document[requestFullScreen.cancelFn]();
  2958. //alert("ray_cancel0");
  2959. this.trigger('play');
  2960. } else {
  2961. this._exitFullWindow();
  2962. this.trigger('cancelFullScreen');
  2963. this.trigger('play');
  2964. }
  2965. return this;
  2966. };
  2967. /**
  2968. * 是否处于全屏
  2969. *
  2970. * @method getIsFullScreen
  2971. * @return {Boolean} 是否为全屏
  2972. */
  2973. Player.prototype.getIsFullScreen = function() {
  2974. return this.isFullScreen;
  2975. };
  2976. /**
  2977. * 获取已经缓存的时间区间
  2978. *
  2979. * @method getBuffered
  2980. * @return {Array} 时间区间数组timeRanges
  2981. */
  2982. Player.prototype.getBuffered = function() {
  2983. return this.tag.buffered;
  2984. };
  2985. //设置是否启用toast信息提示
  2986. Player.prototype.setToastEnabled=function(enabled){
  2987. //for flash
  2988. //this._invoke('setToastEnabled');
  2989. };
  2990. //设置是否显示loading
  2991. Player.prototype.setLoadingInvisible=function(){
  2992. //for flash
  2993. //this_invoke('setLoadingInvisible');
  2994. }
  2995. module.exports = Player;
  2996. },{"../lib/dom":5,"../lib/event":6,"../lib/io":8,"../lib/object":10,"../lib/ua":12,"../monitor/monitor":15,"../ui/component":18,"../ui/exports":27}],18:[function(require,module,exports){
  2997. var oo = require('../lib/oo');
  2998. var Data = require('../lib/data');
  2999. var _ = require('../lib/object');
  3000. var Dom = require('../lib/dom');
  3001. var Event = require('../lib/event');
  3002. var Fn = require('../lib/function');
  3003. var Layout = require('../lib/layout');
  3004. var Component = oo.extend({
  3005. init: function (player, options) {
  3006. var that = this;
  3007. this._player = player;
  3008. // Make a copy of prototype.options_ to protect against overriding global defaults
  3009. this._options = _.copy(options);
  3010. this._el = this.createEl();
  3011. this._id = player.id() + '_component_' + Data.guid();
  3012. this._children = [];
  3013. this._childIndex = {};
  3014. // 只有组件真正被添加到dom树中后再同步ui、绑定事件
  3015. // 从而避免获取不到dom元素
  3016. this._player.on('uiH5Ready', function() {
  3017. that.renderUI();
  3018. that.syncUI();
  3019. that.bindEvent();
  3020. });
  3021. }
  3022. });
  3023. /**
  3024. * 渲染ui
  3025. */
  3026. Component.prototype.renderUI = function() {
  3027. // 根据ui组件的配置渲染layout
  3028. Layout.render(this.el(), this.options());
  3029. // 设置id
  3030. this.el().id = this.id();
  3031. };
  3032. /**
  3033. * 同步ui状态,子类中实现
  3034. */
  3035. Component.prototype.syncUI = function() {};
  3036. /**
  3037. * 绑定事件,子类中实现
  3038. */
  3039. Component.prototype.bindEvent = function() {};
  3040. /**
  3041. * 生成compoent的dom元素
  3042. *
  3043. */
  3044. Component.prototype.createEl = function(tagName, attributes){
  3045. return Dom.createEl(tagName, attributes);
  3046. };
  3047. /**
  3048. * 获取component的所有配置项
  3049. *
  3050. */
  3051. Component.prototype.options = function(obj){
  3052. if (obj === undefined) return this._options;
  3053. return this._options = _.merge(this._options, obj);
  3054. };
  3055. /**
  3056. * 获取componet的dom元素
  3057. *
  3058. */
  3059. Component.prototype.el = function(){
  3060. return this._el;
  3061. };
  3062. Component.prototype._contentEl;
  3063. Component.prototype.player = function(){
  3064. return this._player;
  3065. }
  3066. /**
  3067. * Return the component's DOM element for embedding content.
  3068. * Will either be el_ or a new element defined in createEl.
  3069. *
  3070. * @return {Element}
  3071. */
  3072. Component.prototype.contentEl = function(){
  3073. return this._contentEl || this._el;
  3074. };
  3075. /**
  3076. * 设置元素id
  3077. *
  3078. */
  3079. Component.prototype._id;
  3080. /**
  3081. * 获取元素id
  3082. *
  3083. */
  3084. Component.prototype.id = function(){
  3085. return this._id;
  3086. };
  3087. /* 子元素相关操作
  3088. ============================================================================= */
  3089. /**
  3090. * 添加所有子元素
  3091. *
  3092. */
  3093. Component.prototype.addChild = function(child, options){
  3094. var component, componentClass, componentName, componentId;
  3095. // 如果child是一个字符串
  3096. if(typeof child === 'string'){
  3097. if(!this._player.UI[child]) return;
  3098. component = new this._player.UI[child](this._player,options);
  3099. }else{
  3100. // child是一个compnent对象
  3101. component = child;
  3102. }
  3103. //
  3104. this._children.push(component);
  3105. if (typeof component.id === 'function') {
  3106. this._childIndex[component.id()] = component;
  3107. }
  3108. // 把子元素的dom元素插入父元素中
  3109. if (typeof component['el'] === 'function' && component['el']()) {
  3110. this.contentEl().appendChild(component['el']());
  3111. }
  3112. // 返回添加的子元素
  3113. return component;
  3114. };
  3115. /**
  3116. * 删除指定的子元素
  3117. *
  3118. */
  3119. Component.prototype.removeChild = function(component){
  3120. if (!component || !this._children) return;
  3121. var childFound = false;
  3122. for (var i = this._children.length - 1; i >= 0; i--) {
  3123. if (this._children[i] === component) {
  3124. childFound = true;
  3125. this._children.splice(i,1);
  3126. break;
  3127. }
  3128. }
  3129. if (!childFound) return;
  3130. this._childIndex[component.id] = null;
  3131. var compEl = component.el();
  3132. if (compEl && compEl.parentNode === this.contentEl()) {
  3133. this.contentEl().removeChild(component.el());
  3134. }
  3135. };
  3136. /**
  3137. * 初始化所有子元素
  3138. *
  3139. */
  3140. Component.prototype.initChildren = function(){
  3141. var parent, children, child, name, opts;
  3142. parent = this;
  3143. children = this.options()['children'];
  3144. if (children) {
  3145. // 如果多个子元素是一个数组
  3146. if (_.isArray(children)) {
  3147. for (var i = 0; i < children.length; i++) {
  3148. child = children[i];
  3149. if (typeof child == 'string') {
  3150. name = child;
  3151. opts = {};
  3152. } else {
  3153. name = child.name;
  3154. opts = child;
  3155. }
  3156. parent.addChild(name, opts);
  3157. }
  3158. } else {
  3159. _.each(children, function(name, opts){
  3160. // Allow for disabling default components
  3161. // e.g. vjs.options['children']['posterImage'] = false
  3162. if (opts === false) return;
  3163. parent.addChild(name, opts);
  3164. });
  3165. }
  3166. }
  3167. };
  3168. /* 事件操作
  3169. ============================================================================= */
  3170. /**
  3171. * 在component上的的dom元素上添加一个事件监听器
  3172. *
  3173. * var myFunc = function(){
  3174. * var myPlayer = this;
  3175. * // Do something when the event is fired
  3176. * };
  3177. *
  3178. * myPlayer.on("eventName", myFunc);
  3179. *
  3180. * The context will be the component.
  3181. *
  3182. * @param {String} type The event type e.g. 'click'
  3183. * @param {Function} fn The event listener
  3184. * @return {Component} self
  3185. */
  3186. Component.prototype.on = function(type, fn){
  3187. Event.on(this._el, type, Fn.bind(this, fn));
  3188. return this;
  3189. };
  3190. /**
  3191. * 从component上删除指定事件的监听器
  3192. *
  3193. * myComponent.off("eventName", myFunc);
  3194. *
  3195. * @param {String=} type Event type. Without type it will remove all listeners.
  3196. * @param {Function=} fn Event listener. Without fn it will remove all listeners for a type.
  3197. * @return {Component}
  3198. */
  3199. Component.prototype.off = function(type, fn){
  3200. Event.off(this._el, type, fn);
  3201. return this;
  3202. };
  3203. /**
  3204. * 在组件的元素上添加一个只执行一次的事件监听器
  3205. *
  3206. * @param {String} type Event type
  3207. * @param {Function} fn Event listener
  3208. * @return {Component}
  3209. */
  3210. Component.prototype.one = function(type, fn) {
  3211. Event.one(this._el, type, Fn.bind(this, fn));
  3212. return this;
  3213. };
  3214. /**
  3215. * 在组件的元素上触发一个事件
  3216. */
  3217. Component.prototype.trigger = function(event,paramData){
  3218. //
  3219. if(paramData){
  3220. this._el.paramData = paramData;
  3221. }
  3222. Event.trigger(this._el, event);
  3223. return this;
  3224. };
  3225. /* 组件展现
  3226. ============================================================================= */
  3227. /**
  3228. * 在component上添加指定的className
  3229. *
  3230. * @param {String} classToAdd Classname to add
  3231. * @return {Component}
  3232. */
  3233. Component.prototype.addClass = function(classToAdd){
  3234. Dom.addClass(this._el, classToAdd);
  3235. return this;
  3236. };
  3237. /**
  3238. * 从component删除指定的className
  3239. *
  3240. * @param {String} classToRemove Classname to remove
  3241. * @return {Component}
  3242. */
  3243. Component.prototype.removeClass = function(classToRemove){
  3244. Dom.removeClass(this._el, classToRemove);
  3245. return this;
  3246. };
  3247. /**
  3248. * 显示组件
  3249. *
  3250. * @return {Component}
  3251. */
  3252. Component.prototype.show = function(){
  3253. this._el.style.display = 'block';
  3254. return this;
  3255. };
  3256. /**
  3257. * 隐藏组件
  3258. *
  3259. * @return {Component}
  3260. */
  3261. Component.prototype.hide = function(){
  3262. this._el.style.display = 'none';
  3263. return this;
  3264. };
  3265. /**
  3266. * 销毁component
  3267. *
  3268. * @return
  3269. */
  3270. Component.prototype.destroy = function(){
  3271. this.trigger({ type: 'destroy', 'bubbles': false });
  3272. // 销毁所有子元素
  3273. if (this._children) {
  3274. for (var i = this._children.length - 1; i >= 0; i--) {
  3275. if (this._children[i].destroy) {
  3276. this._children[i].destroy();
  3277. }
  3278. }
  3279. }
  3280. // 删除所有children引用
  3281. this.children_ = null;
  3282. this.childIndex_ = null;
  3283. // 删除所有事件监听器.
  3284. this.off();
  3285. // 从dom中删除所有元素
  3286. if (this._el.parentNode) {
  3287. this._el.parentNode.removeChild(this._el);
  3288. }
  3289. // 删除所有data引用
  3290. Data.removeData(this._el);
  3291. this._el = null;
  3292. };
  3293. module.exports = Component;
  3294. },{"../lib/data":4,"../lib/dom":5,"../lib/event":6,"../lib/function":7,"../lib/layout":9,"../lib/object":10,"../lib/oo":11}],19:[function(require,module,exports){
  3295. /**
  3296. * @fileoverview 大播放按钮
  3297. */
  3298. var Component = require('../component');
  3299. var Dom = require('../../lib/dom');
  3300. var BigPlayButton = Component.extend({
  3301. init: function (player, options) {
  3302. var that = this;
  3303. Component.call(this, player, options);
  3304. this.addClass(options.className || 'prism-big-play-btn');
  3305. },
  3306. bindEvent: function() {
  3307. var that = this;
  3308. this._player.on('canplay', function(){
  3309. that.addClass('playing');
  3310. Dom.css(that.el(), 'display', 'none');
  3311. });
  3312. this._player.on('pause', function(){
  3313. that.removeClass('playing');
  3314. Dom.css(that.el(), 'display', 'block');
  3315. });
  3316. this.on('click', function() {
  3317. if (that._player.paused()) {
  3318. that._player.play();
  3319. Dom.css(that.el(), 'display', 'none');
  3320. }
  3321. });
  3322. }
  3323. });
  3324. module.exports = BigPlayButton;
  3325. },{"../../lib/dom":5,"../component":18}],20:[function(require,module,exports){
  3326. /**
  3327. * @fileoverview 控制条组件
  3328. */
  3329. var Component = require('../component');
  3330. var ControlBar = Component.extend({
  3331. init: function(player,options) {
  3332. Component.call(this, player, options);
  3333. this.addClass(options.className || 'prism-controlbar');
  3334. this.initChildren();
  3335. this.onEvent();
  3336. },
  3337. createEl: function() {
  3338. var el = Component.prototype.createEl.call(this);
  3339. el.innerHTML = '<div class="prism-controlbar-bg"></div>'
  3340. return el;
  3341. },
  3342. onEvent: function(){
  3343. var player = this.player();
  3344. var that = this;
  3345. this.timer = null;
  3346. player.on('click',function(e){
  3347. e.preventDefault();
  3348. e.stopPropagation();
  3349. that._show();
  3350. that._hide();
  3351. });
  3352. player.on('ready',function(){
  3353. that._hide();
  3354. });
  3355. this.on('touchstart', function() {
  3356. that._show();
  3357. });
  3358. this.on('touchmove', function() {
  3359. that._show();
  3360. });
  3361. this.on('touchend', function() {
  3362. that._hide();
  3363. });
  3364. },
  3365. _show: function() {
  3366. this.show();
  3367. if (this.timer) {
  3368. clearTimeout(this.timer);
  3369. this.timer = null;
  3370. }
  3371. },
  3372. _hide: function(){
  3373. var that = this;
  3374. this.timer = setTimeout(function(){
  3375. that.hide();
  3376. }, 5000);
  3377. }
  3378. });
  3379. module.exports = ControlBar;
  3380. },{"../component":18}],21:[function(require,module,exports){
  3381. /**
  3382. * @fileoverview 全屏按钮
  3383. */
  3384. var Component = require('../component');
  3385. var FullScreenButton = Component.extend({
  3386. init: function (player,options) {
  3387. var that = this;
  3388. Component.call(this, player, options);
  3389. this.addClass(options.className || 'prism-fullscreen-btn');
  3390. },
  3391. bindEvent: function() {
  3392. var that = this;
  3393. this._player.on('requestFullScreen', function() {
  3394. that.addClass('fullscreen');
  3395. });
  3396. this._player.on('cancelFullScreen', function() {
  3397. that.removeClass('fullscreen');
  3398. });
  3399. this.on('click', function() {
  3400. //alert("click_full_status:" + this._player.getIsFullScreen());
  3401. if (!this._player.getIsFullScreen()) {
  3402. this._player.requestFullScreen();
  3403. } else {
  3404. this._player.cancelFullScreen();
  3405. }
  3406. });
  3407. }
  3408. });
  3409. module.exports = FullScreenButton;
  3410. },{"../component":18}],22:[function(require,module,exports){
  3411. /**
  3412. * @fileoverview 直播状态 icon
  3413. */
  3414. var Component = require('../component');
  3415. var Util = require('../../lib/util');
  3416. var LiveDisplay = Component.extend({
  3417. init: function (player,options) {
  3418. var that = this;
  3419. Component.call(this, player, options);
  3420. this.className = options.className ? options.className : 'prism-live-display';
  3421. this.addClass(this.className);
  3422. }
  3423. });
  3424. module.exports = LiveDisplay;
  3425. },{"../../lib/util":14,"../component":18}],23:[function(require,module,exports){
  3426. /**
  3427. * @fileoverview 播放按钮
  3428. */
  3429. var Component = require('../component');
  3430. var PlayButton = Component.extend({
  3431. init: function (player, options) {
  3432. var that = this;
  3433. Component.call(this, player, options);
  3434. this.addClass(options.className || 'prism-play-btn');
  3435. },
  3436. bindEvent: function() {
  3437. var that = this;
  3438. this._player.on('play', function(){
  3439. that.addClass('playing');
  3440. });
  3441. this._player.on('pause', function(){
  3442. that.removeClass('playing');
  3443. });
  3444. this.on('click', function() {
  3445. //alert("click_play:" + that._player.paused())
  3446. if (that._player.paused()) {
  3447. that._player.play();
  3448. that.addClass('playing');
  3449. } else {
  3450. that._player.pause();
  3451. that.removeClass('playing');
  3452. }
  3453. });
  3454. }
  3455. });
  3456. module.exports = PlayButton;
  3457. },{"../component":18}],24:[function(require,module,exports){
  3458. /**
  3459. * @fileoverview 进度条
  3460. */
  3461. var Component = require('../component');
  3462. var Dom = require('../../lib/dom');
  3463. var Event = require('../../lib/event');
  3464. var UA = require('../../lib/ua');
  3465. var Fn = require('../../lib/function');
  3466. var Progress = Component.extend({
  3467. init: function (player, options) {
  3468. var that = this;
  3469. Component.call(this, player, options);
  3470. this.className = options.className ? options.className : 'prism-progress';
  3471. this.addClass(this.className);
  3472. },
  3473. createEl: function() {
  3474. var el = Component.prototype.createEl.call(this);
  3475. el.innerHTML = '<div class="prism-progress-loaded"></div>'
  3476. + '<div class="prism-progress-played"></div>'
  3477. + '<div class="prism-progress-cursor"></div>';
  3478. return el;
  3479. },
  3480. bindEvent: function() {
  3481. var that = this;
  3482. this.loadedNode = document.querySelector('#' + this.id() + ' .prism-progress-loaded');
  3483. this.playedNode = document.querySelector('#' + this.id() + ' .prism-progress-played');
  3484. this.cursorNode = document.querySelector('#' + this.id() + ' .prism-progress-cursor');
  3485. Event.on(this.cursorNode, 'mousedown', function(e) {that._onMouseDown(e);});
  3486. Event.on(this.cursorNode, 'touchstart', function(e) {that._onMouseDown(e);});
  3487. this._player.on('hideProgress', function(e) {that._hideProgress(e);});
  3488. this._player.on('cancelHideProgress', function(e) {that._cancelHideProgress(e);});
  3489. this.bindTimeupdate = Fn.bind(this, this._onTimeupdate);
  3490. this._player.on('timeupdate', this.bindTimeupdate);
  3491. // ipad下播放无法触发progress事件,原因待查
  3492. if (UA.IS_IPAD) {
  3493. this.interval = setInterval(function() {
  3494. that._onProgress();
  3495. }, 500);
  3496. } else {
  3497. this._player.on('progress', function() {that._onProgress();});
  3498. }
  3499. },
  3500. //取消控制进度条
  3501. _hideProgress: function(e) {
  3502. var that = this;
  3503. console.log("hidestart");
  3504. Event.off(this.cursorNode, 'mousedown');
  3505. Event.off(this.cursorNode, 'touchstart');
  3506. },
  3507. //打开控制进度条
  3508. _cancelHideProgress: function(e) {
  3509. var that = this;
  3510. console.log("hidestop");
  3511. Event.on(this.cursorNode, 'mousedown', function(e) {that._onMouseDown(e);});
  3512. Event.on(this.cursorNode, 'touchstart', function(e) {that._onMouseDown(e);});
  3513. },
  3514. _onMouseDown: function(e) {
  3515. var that = this;
  3516. e.preventDefault();
  3517. //e.stopPropagation();
  3518. this._player.pause();
  3519. this._player.trigger('seekStart', {fromTime: this._player.getCurrentTime()});
  3520. console.log("seekstart");
  3521. //alert("progress_seekstart");
  3522. Event.on(this.cursorNode, 'mousemove', function(e) {that._onMouseMove(e);});
  3523. Event.on(this.cursorNode, 'mouseup', function(e) {that._onMouseUp(e);});
  3524. Event.on(this.cursorNode, 'touchmove', function(e) {that._onMouseMove(e);});
  3525. Event.on(this.cursorNode, 'touchend', function(e) {that._onMouseUp(e);});
  3526. },
  3527. _onMouseUp: function(e) {
  3528. var that = this;
  3529. e.preventDefault();
  3530. //e.stopPropagation();
  3531. Event.off(this.cursorNode, 'mousemove');
  3532. Event.off(this.cursorNode, 'mouseup');
  3533. Event.off(this.cursorNode, 'touchmove');
  3534. Event.off(this.cursorNode, 'touchend');
  3535. // 设置当前时间,播放视频
  3536. var sec = this.playedNode.offsetWidth / this.el().offsetWidth * this._player.getDuration();
  3537. var sec_now = this._player.getDuration();
  3538. this._player.seek(sec);
  3539. this._player.play();
  3540. this._player.trigger('seekEnd', {toTime: this._player.getCurrentTime()});
  3541. console.log("seekend");
  3542. //alert("progress_seekend");
  3543. },
  3544. _onMouseMove: function(e) {
  3545. e.preventDefault();
  3546. //e.stopPropagation();
  3547. var pageX = e.touches? e.touches[0].pageX: e.pageX,
  3548. distance = pageX - this.el().offsetLeft,
  3549. width = this.el().offsetWidth,
  3550. sec = (this._player.getDuration()) ? distance / width * this._player.getDuration(): 0;
  3551. if (sec < 0) sec = 0;
  3552. if (sec > this._player.getDuration()) sec = this._player.getDuration();
  3553. this._player.seek(sec);
  3554. //this._updateProgressBar(this.playedNode, sec);
  3555. //this._updateCursorPosition(sec);
  3556. },
  3557. _onTimeupdate: function(e) {
  3558. // ios下
  3559. // 为了解决seek会跳转到原来的位置,需要进入lock的机制。。。丑陋的代码
  3560. // 只有当前时刻与seekto的时刻间隔小于1秒,并且连续三次,才放开lock
  3561. /*
  3562. if (S.UA.ios) {
  3563. var thre = Math.abs(this._player.getCurrentTime() - this._player.getLastSeekTime());
  3564. if (this._player.getSeekLock()) {
  3565. if (thre < 1 && this.lockCount > 3) {
  3566. this._player.setSeekLock(false);
  3567. this.lockCount = 1;
  3568. } else if (thre < 1){
  3569. this.lockCount++;
  3570. }
  3571. }
  3572. if (!this._player.getSeekLock() ) {
  3573. this._updateProgressBar(this.playedNode, this._player.getCurrentTime());
  3574. this._updateCursorPosition(this._player.getCurrentTime());
  3575. this._updateTip(this._player.getCurrentTime());
  3576. this._player.fire('updateProgressBar', {
  3577. time: this._player.getCurrentTime()
  3578. });
  3579. }
  3580. } else {
  3581. */
  3582. this._updateProgressBar(this.playedNode, this._player.getCurrentTime());
  3583. this._updateCursorPosition(this._player.getCurrentTime());
  3584. this._player.trigger('updateProgressBar', {
  3585. time: this._player.getCurrentTime()
  3586. });
  3587. //}
  3588. },
  3589. _onProgress: function(e) {
  3590. // 此时buffer可能还没有准备好
  3591. if (this._player.getDuration()) {
  3592. this._updateProgressBar(this.loadedNode, this._player.getBuffered().end(this._player.getBuffered().length - 1));
  3593. }
  3594. },
  3595. _updateProgressBar: function(node, sec) {
  3596. var percent = (this._player.getDuration()) ? sec / this._player.getDuration(): 0;
  3597. if (node) {
  3598. Dom.css(node, 'width', (percent * 100) + '%');
  3599. };
  3600. },
  3601. _updateCursorPosition: function(sec) {
  3602. var percent = (this._player.getDuration()) ? sec / this._player.getDuration(): 0;
  3603. if (this.cursorNode) {
  3604. Dom.css(this.cursorNode, 'left', (percent * 100) + '%');
  3605. };
  3606. }
  3607. });
  3608. module.exports = Progress;
  3609. },{"../../lib/dom":5,"../../lib/event":6,"../../lib/function":7,"../../lib/ua":12,"../component":18}],25:[function(require,module,exports){
  3610. /**
  3611. * @fileoverview 播放时间
  3612. */
  3613. var Component = require('../component');
  3614. var Util = require('../../lib/util');
  3615. var TimeDisplay = Component.extend({
  3616. init: function (player,options) {
  3617. var that = this;
  3618. Component.call(this, player, options);
  3619. this.className = options.className ? options.className : 'prism-time-display';
  3620. this.addClass(this.className);
  3621. },
  3622. createEl: function() {
  3623. var el = Component.prototype.createEl.call(this,'div');
  3624. el.innerHTML = '<span class="current-time">00:00</span> <span class="time-bound">/</span> <span class="duration">00:00</span>';
  3625. return el;
  3626. },
  3627. bindEvent: function() {
  3628. var that = this;
  3629. this._player.on('durationchange', function() {
  3630. var dur = Util.formatTime(that._player.getDuration());
  3631. if (dur) {
  3632. document.querySelector('#' + that.id() + ' .duration').innerText = dur;
  3633. } else {
  3634. document.querySelector('#' + that.id() + ' .duration').style.display = 'none';
  3635. document.querySelector('#' + that.id() + ' .time-bound').style.display = 'none';
  3636. }
  3637. });
  3638. this._player.on('timeupdate', function() {
  3639. //var curr_time = that._player.getCurrentTime();
  3640. var curr = Util.formatTime(that._player.getCurrentTime());
  3641. /*
  3642. if (!this._player.last_curT) {
  3643. this._player.last_curT = curr_time;
  3644. }
  3645. else {
  3646. var diff = curr - this._player.last_curT;
  3647. console.log("diff_time" + diff);
  3648. this._player.last_curT = curr_time;
  3649. }
  3650. */
  3651. if (curr) {
  3652. document.querySelector('#' + that.id() + ' .current-time').innerText = curr;
  3653. } else {
  3654. document.querySelector('#' + that.id() + ' .current-time').style.display = 'none';
  3655. }
  3656. });
  3657. }
  3658. });
  3659. module.exports = TimeDisplay;
  3660. },{"../../lib/util":14,"../component":18}],26:[function(require,module,exports){
  3661. /**
  3662. * @fileoverview 音量按钮,h5下只做静音非静音的控制
  3663. */
  3664. var Component = require('../component');
  3665. var Volume = Component.extend({
  3666. init: function (player, options) {
  3667. var that = this;
  3668. Component.call(this, player, options);
  3669. this.addClass(options.className || 'prism-volume');
  3670. },
  3671. bindEvent: function() {
  3672. var that = this;
  3673. this.on('click', function() {
  3674. if (that._player.muted()) {
  3675. that._player.unMute();
  3676. that.removeClass('mute');
  3677. } else {
  3678. that._player.mute();
  3679. that.addClass('mute');
  3680. }
  3681. });
  3682. }
  3683. });
  3684. module.exports = Volume;
  3685. },{"../component":18}],27:[function(require,module,exports){
  3686. /**
  3687. * @fileoverview ui组件列表,fullversion会将定义的所有ui组件列于此做统一加载
  3688. * 后期补上根据实际需求配置组件列表,从而一定程度上减少体积
  3689. * @author 首作<aloysious.ld@taobao.com>
  3690. * @date 2015-01-05
  3691. */
  3692. module.exports = {
  3693. 'bigPlayButton' : require('./component/big-play-button'),
  3694. 'controlBar' : require('./component/controlbar'),
  3695. 'progress' : require('./component/progress'),
  3696. 'playButton' : require('./component/play-button'),
  3697. 'liveDisplay' : require('./component/live-display'),
  3698. 'timeDisplay' : require('./component/time-display'),
  3699. 'fullScreenButton': require('./component/fullscreen-button'),
  3700. 'volume' : require('./component/volume')
  3701. };
  3702. },{"./component/big-play-button":19,"./component/controlbar":20,"./component/fullscreen-button":21,"./component/live-display":22,"./component/play-button":23,"./component/progress":24,"./component/time-display":25,"./component/volume":26}]},{},[2]);