|
1 /*! |
|
2 |
|
3 Flowplayer v6.0.3 (Thursday, 23. July 2015 09:32PM) | flowplayer.org/license |
|
4 |
|
5 */ |
|
6 /*! (C) WebReflection Mit Style License */ |
|
7 (function(e){function m(e,t,n,r){for(var i,s=n.slice(),o=b(t,e),u=0,a=s.length;u<a;u++){handler=s[u],typeof handler=="object"&&typeof handler.handleEvent=="function"?handler.handleEvent(o):handler.call(e,o);if(o.stoppedImmediatePropagation)break}return i=!o.stoppedPropagation,r&&i&&e.parentNode?e.parentNode.dispatchEvent(o):!o.defaultPrevented}function g(e,t){return{configurable:!0,get:e,set:t}}function y(e,t,n){var r=a(t||e,n);o(e,"textContent",g(function(){return r.get.call(this)},function(e){r.set.call(this,e)}))}function b(e,t){return e.currentTarget=t,e.eventPhase=e.target===e.currentTarget?2:3,e}function w(e,t){var n=e.length;while(n--&&e[n]!==t);return n}function E(){if(this.tagName==="BR")return"\n";var e=this.firstChild,t=[];while(e)e.nodeType!==8&&e.nodeType!==7&&t.push(e.textContent),e=e.nextSibling;return t.join("")}function S(e){return e.nodeType!==9&&document.documentElement.contains(e)}function x(e){var t=document.createEvent("Event");t.initEvent("input",!0,!0),(e.srcElement||e.fromElement||document).dispatchEvent(t)}function T(e){!n&&p.test(document.readyState)&&(n=!n,document.detachEvent(r,T),e=document.createEvent("Event"),e.initEvent(i,!0,!0),document.dispatchEvent(e))}function N(e){var t;while(t=this.lastChild)this.removeChild(t);e!=null&&this.appendChild(document.createTextNode(e))}function C(t,n){return n||(n=e.event),n.target||(n.target=n.srcElement||n.fromElement||document),n.timeStamp||(n.timeStamp=(new Date).getTime()),n}if(document.createEvent)return;var t=!0,n=!1,r="onreadystatechange",i="DOMContentLoaded",s="__IE8__"+Math.random(),o=Object.defineProperty||function(e,t,n){e[t]=n.value},u=Object.defineProperties||function(t,n){for(var r in n)if(f.call(n,r))try{o(t,r,n[r])}catch(i){e.console&&console.log(r+" failed on object:",t,i.message)}},a=Object.getOwnPropertyDescriptor,f=Object.prototype.hasOwnProperty,l=e.Element.prototype,c=e.Text.prototype,h=/^[a-z]+$/,p=/loaded|complete/,d={},v=document.createElement("div");y(e.HTMLCommentElement.prototype,l,"nodeValue"),y(e.HTMLScriptElement.prototype,null,"text"),y(c,null,"nodeValue"),y(e.HTMLTitleElement.prototype,null,"text"),o(e.HTMLStyleElement.prototype,"textContent",function(e){return g(function(){return e.get.call(this.styleSheet)},function(t){e.set.call(this.styleSheet,t)})}(a(e.CSSStyleSheet.prototype,"cssText"))),u(l,{textContent:{get:E,set:N},firstElementChild:{get:function(){for(var e=this.childNodes||[],t=0,n=e.length;t<n;t++)if(e[t].nodeType==1)return e[t]}},lastElementChild:{get:function(){for(var e=this.childNodes||[],t=e.length;t--;)if(e[t].nodeType==1)return e[t]}},oninput:{get:function(){return this._oninput||null},set:function(e){this._oninput&&(this.removeEventListener("input",this._oninput),this._oninput=e,e&&this.addEventListener("input",e))}},previousElementSibling:{get:function(){var e=this.previousSibling;while(e&&e.nodeType!=1)e=e.previousSibling;return e}},nextElementSibling:{get:function(){var e=this.nextSibling;while(e&&e.nodeType!=1)e=e.nextSibling;return e}},childElementCount:{get:function(){for(var e=0,t=this.childNodes||[],n=t.length;n--;e+=t[n].nodeType==1);return e}},addEventListener:{value:function(e,t,n){var r=this,i="on"+e,u=r[s]||o(r,s,{value:{}})[s],a=u[i]||(u[i]={}),l=a.h||(a.h=[]),c;if(!f.call(a,"w")){a.w=function(e){return e[s]||m(r,C(r,e),l,!1)};if(!f.call(d,i))if(h.test(e))try{c=document.createEventObject(),c[s]=!0,r.nodeType!=9&&r.parentNode==null&&v.appendChild(r),r.fireEvent(i,c),d[i]=!0}catch(c){d[i]=!1;while(v.hasChildNodes())v.removeChild(v.firstChild)}else d[i]=!1;(a.n=d[i])&&r.attachEvent(i,a.w)}w(l,t)<0&&l[n?"unshift":"push"](t),e==="input"&&r.attachEvent("onkeyup",x)}},dispatchEvent:{value:function(e){var t=this,n="on"+e.type,r=t[s],i=r&&r[n],o=!!i,u;return e.target||(e.target=t),o?i.n?t.fireEvent(n,e):m(t,e,i.h,!0):(u=t.parentNode)?u.dispatchEvent(e):!0,!e.defaultPrevented}},removeEventListener:{value:function(e,t,n){var r=this,i="on"+e,o=r[s],u=o&&o[i],a=u&&u.h,f=a?w(a,t):-1;-1<f&&a.splice(f,1)}}}),u(c,{addEventListener:{value:l.addEventListener},dispatchEvent:{value:l.dispatchEvent},removeEventListener:{value:l.removeEventListener}}),u(e.XMLHttpRequest.prototype,{addEventListener:{value:function(e,t,n){var r=this,i="on"+e,u=r[s]||o(r,s,{value:{}})[s],a=u[i]||(u[i]={}),f=a.h||(a.h=[]);w(f,t)<0&&(r[i]||(r[i]=function(){var t=document.createEvent("Event");t.initEvent(e,!0,!0),r.dispatchEvent(t)}),f[n?"unshift":"push"](t))}},dispatchEvent:{value:function(e){var t=this,n="on"+e.type,r=t[s],i=r&&r[n],o=!!i;return o&&(i.n?t.fireEvent(n,e):m(t,e,i.h,!0))}},removeEventListener:{value:l.removeEventListener}}),u(e.Event.prototype,{bubbles:{value:!0,writable:!0},cancelable:{value:!0,writable:!0},preventDefault:{value:function(){this.cancelable&&(this.defaultPrevented=!0,this.returnValue=!1)}},stopPropagation:{value:function(){this.stoppedPropagation=!0,this.cancelBubble=!0}},stopImmediatePropagation:{value:function(){this.stoppedImmediatePropagation=!0,this.stopPropagation()}},initEvent:{value:function(e,t,n){this.type=e,this.bubbles=!!t,this.cancelable=!!n,this.bubbles||this.stopPropagation()}}}),u(e.HTMLDocument.prototype,{defaultView:{get:function(){return this.parentWindow}},textContent:{get:function(){return this.nodeType===11?E.call(this):null},set:function(e){this.nodeType===11&&N.call(this,e)}},addEventListener:{value:function(n,s,o){var u=this;l.addEventListener.call(u,n,s,o),t&&n===i&&!p.test(u.readyState)&&(t=!1,u.attachEvent(r,T),e==top&&function a(e){try{u.documentElement.doScroll("left"),T()}catch(t){setTimeout(a,50)}}())}},dispatchEvent:{value:l.dispatchEvent},removeEventListener:{value:l.removeEventListener},createEvent:{value:function(e){var t;if(e!=="Event")throw new Error("unsupported "+e);return t=document.createEventObject(),t.timeStamp=(new Date).getTime(),t}}}),u(e.Window.prototype,{getComputedStyle:{value:function(){function i(e){this._=e}function s(){}var e=/^(?:[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|))(?!px)[a-z%]+$/,t=/^(top|right|bottom|left)$/,n=/\-([a-z])/g,r=function(e,t){return t.toUpperCase()};return i.prototype.getPropertyValue=function(i){var s=this._,o=s.style,u=s.currentStyle,a=s.runtimeStyle,f,l,c;return i=(i==="float"?"style-float":i).replace(n,r),f=u?u[i]:o[i],e.test(f)&&!t.test(i)&&(l=o.left,c=a&&a.left,c&&(a.left=u.left),o.left=i==="fontSize"?"1em":f,f=o.pixelLeft+"px",o.left=l,c&&(a.left=c)),f==null?f:f+""||"auto"},s.prototype.getPropertyValue=function(){return null},function(e,t){return t?new s(e):new i(e)}}()},addEventListener:{value:function(t,n,r){var i=e,o="on"+t,u;i[o]||(i[o]=function(e){return m(i,C(i,e),u,!1)}),u=i[o][s]||(i[o][s]=[]),w(u,n)<0&&u[r?"unshift":"push"](n)}},dispatchEvent:{value:function(t){var n=e["on"+t.type];return n?n.call(e,t)!==!1&&!t.defaultPrevented:!0}},removeEventListener:{value:function(t,n,r){var i="on"+t,o=(e[i]||Object)[s],u=o?w(o,n):-1;-1<u&&o.splice(u,1)}}})})(this); |
|
8 !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.flowplayer=e()}}(function(){var define,module,exports;return (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(_dereq_,module,exports){ |
|
9 'use strict'; |
|
10 var common = module.exports = {}, |
|
11 ClassList = _dereq_('class-list'), |
|
12 $ = window.jQuery, |
|
13 punycode = _dereq_('punycode'), |
|
14 computedStyle = _dereq_('computed-style'); |
|
15 |
|
16 common.noop = function() {}; |
|
17 common.identity = function(i) { return i; }; |
|
18 |
|
19 common.removeNode = function(el) { |
|
20 if (!el || !el.parentNode) return; |
|
21 el.parentNode.removeChild(el); |
|
22 }; |
|
23 |
|
24 common.find = function(query, ctx) { |
|
25 if ($) return $(query, ctx).toArray(); |
|
26 ctx = ctx || document; |
|
27 return Array.prototype.map.call(ctx.querySelectorAll(query), function(el) { return el; }); |
|
28 }; |
|
29 |
|
30 common.text = function(el, txt) { |
|
31 el[('innerText' in el) ? 'innerText' : 'textContent'] = txt; |
|
32 }; |
|
33 |
|
34 common.findDirect = function(query, ctx) { |
|
35 return common.find(query, ctx).filter(function(node) { |
|
36 return node.parentNode === ctx; |
|
37 }); |
|
38 }; |
|
39 |
|
40 common.hasClass = function(el, kls) { |
|
41 return ClassList(el).contains(kls); |
|
42 }; |
|
43 |
|
44 |
|
45 common.css = function(el, property, value) { |
|
46 if (typeof property === 'object') { |
|
47 return Object.keys(property).forEach(function(key) { |
|
48 common.css(el, key, property[key]); |
|
49 }); |
|
50 } |
|
51 if (typeof value !== 'undefined') { |
|
52 if (value === '') return el ? el.style.removeProperty(property) : undefined; |
|
53 return el ? el.style.setProperty(property, value) : undefined; |
|
54 } |
|
55 return el ? computedStyle(el, property) : undefined; |
|
56 }; |
|
57 |
|
58 common.createElement = function(tag, attributes, innerHTML) { |
|
59 try { |
|
60 var el = document.createElement(tag); |
|
61 for (var key in attributes) { |
|
62 if (!attributes.hasOwnProperty(key)) continue; |
|
63 if (key === 'css') { |
|
64 common.css(el, attributes[key]); |
|
65 } else { |
|
66 common.attr(el, key, attributes[key]); |
|
67 } |
|
68 } |
|
69 el.innerHTML = innerHTML || ''; |
|
70 return el; |
|
71 } catch (e) { |
|
72 if (!$) throw e; |
|
73 return $('<' + tag + '>' + innerHTML + '</' + tag + '>').attr(attributes)[0]; |
|
74 } |
|
75 }; |
|
76 |
|
77 common.toggleClass = function(el, cls, flag) { |
|
78 if (!el) return; |
|
79 var classes = ClassList(el); |
|
80 if (typeof flag === 'undefined') classes.toggle(cls); |
|
81 else if (flag) classes.add(cls); |
|
82 else if (!flag) classes.remove(cls); |
|
83 }; |
|
84 |
|
85 common.addClass = function(el, cls) { |
|
86 return common.toggleClass(el, cls, true); |
|
87 }; |
|
88 |
|
89 common.removeClass = function(el, cls) { |
|
90 return common.toggleClass(el, cls, false); |
|
91 }; |
|
92 |
|
93 common.append = function(par, child) { |
|
94 par.appendChild(child); |
|
95 return par; |
|
96 }; |
|
97 |
|
98 common.appendTo = function(child, par) { |
|
99 common.append(par, child); |
|
100 return child; |
|
101 }; |
|
102 |
|
103 common.prepend = function(par, child) { |
|
104 par.insertBefore(child, par.firstChild); |
|
105 }; |
|
106 |
|
107 |
|
108 // Inserts `el` after `child` that is child of `par` |
|
109 common.insertAfter = function(par, child, el) { |
|
110 if (child == common.lastChild(par)) par.appendChild(el); |
|
111 var childIndex = Array.prototype.indexOf.call(par.children, child); |
|
112 par.insertBefore(el, par.children[childIndex + 1]); |
|
113 }; |
|
114 |
|
115 common.html = function(elms, val) { |
|
116 elms = elms.length ? elms : [elms]; |
|
117 elms.forEach(function(elm) { |
|
118 elm.innerHTML = val; |
|
119 }); |
|
120 }; |
|
121 |
|
122 |
|
123 common.attr = function(el, key, val) { |
|
124 if (key === 'class') key = 'className'; |
|
125 if (common.hasOwnOrPrototypeProperty(el, key)) { |
|
126 try { |
|
127 el[key] = val; |
|
128 } catch (e) { // Most likely IE not letting set property |
|
129 if ($) { |
|
130 $(el).attr(key, val); |
|
131 } else { |
|
132 throw e; |
|
133 } |
|
134 } |
|
135 } else { |
|
136 if (val === false) { |
|
137 el.removeAttribute(key); |
|
138 } else { |
|
139 el.setAttribute(key, val); |
|
140 } |
|
141 } |
|
142 return el; |
|
143 }; |
|
144 |
|
145 common.prop = function(el, key, val) { |
|
146 if (typeof val === 'undefined') { |
|
147 return el && el[key]; |
|
148 } |
|
149 el[key] = val; |
|
150 }; |
|
151 |
|
152 common.offset = function(el) { |
|
153 var ret = el.getBoundingClientRect(); |
|
154 if (el.offsetWidth / el.offsetHeight > el.clientWidth / el.clientHeight) { // https://github.com/flowplayer/flowplayer/issues/757 |
|
155 ret = { |
|
156 left: ret.left * 100, |
|
157 right: ret.right * 100, |
|
158 top: ret.top * 100, |
|
159 bottom: ret.bottom * 100, |
|
160 width: ret.width * 100, |
|
161 height: ret.height * 100 |
|
162 }; |
|
163 } |
|
164 return ret; |
|
165 }; |
|
166 |
|
167 common.width = function(el, val) { |
|
168 /*jshint -W093 */ |
|
169 if (val) return el.style.width = (''+val).replace(/px$/, '') + 'px'; |
|
170 var ret = common.offset(el).width; |
|
171 return typeof ret === 'undefined' ? el.offsetWidth : ret; |
|
172 }; |
|
173 |
|
174 common.height = function(el, val) { |
|
175 /*jshint -W093 */ |
|
176 if (val) return el.style.height = (''+val).replace(/px$/, '') + 'px'; |
|
177 var ret = common.offset(el).height; |
|
178 return typeof ret === 'undefined' ? el.offsetHeight : ret; |
|
179 }; |
|
180 |
|
181 common.lastChild = function(el) { |
|
182 return el.children[el.children.length - 1]; |
|
183 }; |
|
184 |
|
185 common.hasParent = function(el, parentSelector) { |
|
186 var parent = el.parentElement; |
|
187 while (parent) { |
|
188 if (common.matches(parent, parentSelector)) return true; |
|
189 parent = parent.parentElement; |
|
190 } |
|
191 return false; |
|
192 }; |
|
193 |
|
194 common.createAbsoluteUrl = function(url) { |
|
195 return common.createElement('a', {href: url}).href; // This won't work on IE7 |
|
196 }; |
|
197 |
|
198 common.xhrGet = function(url, successCb, errorCb) { |
|
199 var xhr = new XMLHttpRequest(); |
|
200 xhr.onreadystatechange = function() { |
|
201 if (this.readyState !== 4) return; |
|
202 if (this.status >= 400) return errorCb(); |
|
203 successCb(this.responseText); |
|
204 }; |
|
205 xhr.open('get', url, true); |
|
206 xhr.send(); |
|
207 }; |
|
208 |
|
209 common.pick = function(obj, props) { |
|
210 var ret = {}; |
|
211 props.forEach(function(prop) { |
|
212 if (obj.hasOwnProperty(prop)) ret[prop] = obj[prop]; |
|
213 }); |
|
214 return ret; |
|
215 }; |
|
216 |
|
217 common.hostname = function(host) { |
|
218 return punycode.toUnicode(host || window.location.hostname); |
|
219 }; |
|
220 |
|
221 //Hacks |
|
222 common.browser = { |
|
223 webkit: 'WebkitAppearance' in document.documentElement.style |
|
224 }; |
|
225 |
|
226 common.getPrototype = function(el) { |
|
227 /* jshint proto:true */ |
|
228 if (!Object.getPrototypeOf) return el.__proto__; |
|
229 return Object.getPrototypeOf(el); |
|
230 }; |
|
231 |
|
232 common.hasOwnOrPrototypeProperty = function(obj, prop) { |
|
233 var o = obj; |
|
234 while (o) { |
|
235 if (Object.prototype.hasOwnProperty.call(o, prop)) return true; |
|
236 o = common.getPrototype(o); |
|
237 } |
|
238 return false; |
|
239 }; |
|
240 |
|
241 |
|
242 // Polyfill for Element.matches |
|
243 // adapted from https://developer.mozilla.org/en/docs/Web/API/Element/matches |
|
244 common.matches = function(elem, selector) { |
|
245 var proto = Element.prototype, |
|
246 fn = proto.matches || |
|
247 proto.matchesSelector || |
|
248 proto.mozMatchesSelector || |
|
249 proto.msMatchesSelector || |
|
250 proto.oMatchesSelector || |
|
251 proto.webkitMatchesSelector || |
|
252 function (selector) { |
|
253 var element = this, |
|
254 matches = (element.document || element.ownerDocument).querySelectorAll(selector), |
|
255 i = 0; |
|
256 while (matches[i] && matches[i] !== element) { |
|
257 i++; |
|
258 } |
|
259 |
|
260 return matches[i] ? true : false; |
|
261 }; |
|
262 return fn.call(elem, selector); |
|
263 }; |
|
264 |
|
265 |
|
266 // Polyfill for CSSStyleDeclaration |
|
267 // from https://github.com/shawnbot/aight |
|
268 (function(CSSSDProto) { |
|
269 |
|
270 function getAttribute(property) { |
|
271 return property.replace(/-[a-z]/g, function(bit) { |
|
272 return bit[1].toUpperCase(); |
|
273 }); |
|
274 } |
|
275 |
|
276 // patch CSSStyleDeclaration.prototype using IE8's methods |
|
277 if (typeof CSSSDProto.setAttribute !== "undefined") { |
|
278 CSSSDProto.setProperty = function(property, value) { |
|
279 return this.setAttribute(getAttribute(property), String(value) /*, important */ ); |
|
280 }; |
|
281 CSSSDProto.getPropertyValue = function(property) { |
|
282 return this.getAttribute(getAttribute(property)) || null; |
|
283 }; |
|
284 CSSSDProto.removeProperty = function(property) { |
|
285 var value = this.getPropertyValue(property); |
|
286 this.removeAttribute(getAttribute(property)); |
|
287 return value; |
|
288 }; |
|
289 } |
|
290 |
|
291 })(window.CSSStyleDeclaration.prototype); |
|
292 |
|
293 },{"class-list":22,"computed-style":24,"punycode":21}],2:[function(_dereq_,module,exports){ |
|
294 /* global __flash_unloadHandler:true,__flash_savedUnloadHandler:true */ |
|
295 'use strict'; |
|
296 var common = _dereq_('../common'); |
|
297 |
|
298 // movie required in opts |
|
299 module.exports = function embed(swf, flashvars, wmode, bgColor) { |
|
300 wmode = wmode || "opaque"; |
|
301 |
|
302 var id = "obj" + ("" + Math.random()).slice(2, 15), |
|
303 tag = '<object class="fp-engine" id="' + id+ '" name="' + id + '" ', |
|
304 msie = navigator.userAgent.indexOf('MSIE') > -1; |
|
305 |
|
306 tag += msie ? 'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">' : |
|
307 ' data="' + swf + '" type="application/x-shockwave-flash">'; |
|
308 |
|
309 var opts = { |
|
310 width: "100%", |
|
311 height: "100%", |
|
312 allowscriptaccess: "always", |
|
313 wmode: wmode, |
|
314 quality: "high", |
|
315 flashvars: "", |
|
316 |
|
317 // https://github.com/flowplayer/flowplayer/issues/13#issuecomment-9369919 |
|
318 movie: swf + (msie ? "?" + id : ""), |
|
319 name: id |
|
320 }; |
|
321 |
|
322 if (wmode !== 'transparent') opts.bgcolor = bgColor || '#333333'; |
|
323 |
|
324 // flashvars |
|
325 Object.keys(flashvars).forEach(function(key) { |
|
326 opts.flashvars += key + "=" + flashvars[key] + "&"; |
|
327 }); |
|
328 |
|
329 // parameters |
|
330 Object.keys(opts).forEach(function(key) { |
|
331 tag += '<param name="' + key + '" value="'+ opts[key] +'"/>'; |
|
332 }); |
|
333 |
|
334 tag += "</object>"; |
|
335 var el = common.createElement('div', {}, tag); |
|
336 return common.find('object', el); |
|
337 |
|
338 }; |
|
339 |
|
340 |
|
341 // Flash is buggy allover |
|
342 if (window.attachEvent) { |
|
343 window.attachEvent("onbeforeunload", function() { |
|
344 __flash_savedUnloadHandler = __flash_unloadHandler = function() {}; |
|
345 }); |
|
346 } |
|
347 |
|
348 |
|
349 },{"../common":1}],3:[function(_dereq_,module,exports){ |
|
350 'use strict'; |
|
351 var flowplayer = _dereq_('../flowplayer'), |
|
352 common = _dereq_('../common'), |
|
353 embed = _dereq_('./embed'), |
|
354 extend = _dereq_('extend-object'), |
|
355 bean = _dereq_('bean'), |
|
356 engineImpl; |
|
357 |
|
358 engineImpl = function flashEngine(player, root) { |
|
359 |
|
360 var conf = player.conf, |
|
361 video = player.video, |
|
362 loadVideo, |
|
363 callbackId, |
|
364 objectTag, |
|
365 api; |
|
366 |
|
367 var win = window; |
|
368 |
|
369 var engine = { |
|
370 engineName: engineImpl.engineName, |
|
371 |
|
372 pick: function(sources) { |
|
373 |
|
374 if (flowplayer.support.flashVideo) { |
|
375 var selectedSource; |
|
376 for (var i = 0, source; i < sources.length; i++) { |
|
377 source = sources[i]; |
|
378 if (/mp4|flv|flash/i.test(source.type)) selectedSource = source; |
|
379 if (player.conf.swfHls && /mpegurl/i.test(source.type)) selectedSource = source; |
|
380 if (selectedSource && !/mp4/i.test(selectedSource.type)) return selectedSource; |
|
381 // Did not find any source or source was video/mp4, let's try find more |
|
382 } |
|
383 return selectedSource; // Accept the fact we don't have anything or just an MP4 |
|
384 } |
|
385 }, |
|
386 |
|
387 load: function(video) { |
|
388 loadVideo = video; |
|
389 |
|
390 function escapeURL(url) { |
|
391 return url.replace(/&/g, '%26').replace(/&/g, '%26').replace(/=/g, '%3D'); |
|
392 } |
|
393 |
|
394 var html5Tag = common.findDirect('video', root)[0] || common.find('.fp-player > video', root)[0], |
|
395 url = escapeURL(video.src), |
|
396 is_absolute = /^https?:/.test(url); |
|
397 |
|
398 var removeTag = function() { |
|
399 common.removeNode(html5Tag); |
|
400 }; |
|
401 var hasSupportedSource = function(sources) { |
|
402 return sources.some(function(src) { |
|
403 return !!html5Tag.canPlayType(src.type); |
|
404 }); |
|
405 }; |
|
406 if (flowplayer.support.video && |
|
407 common.prop(html5Tag, 'autoplay') && |
|
408 hasSupportedSource(video.sources)) bean.one(html5Tag, 'timeupdate', removeTag); |
|
409 else removeTag(); |
|
410 |
|
411 // convert to absolute |
|
412 var rtmp = video.rtmp || conf.rtmp; |
|
413 if (!is_absolute && !rtmp) url = common.createAbsoluteUrl(url); |
|
414 |
|
415 if (api && isHLS(video) && api.data !== conf.swfHls) engine.unload(); |
|
416 |
|
417 if (api) { |
|
418 ['live', 'preload', 'loop'].forEach(function(prop) { |
|
419 if (!video.hasOwnProperty(prop)) return; |
|
420 api.__set(prop, video[prop]); |
|
421 }); |
|
422 Object.keys(video.flashls || {}).forEach(function(key) { |
|
423 api.__set('hls_' + key, video.flashls[key]); |
|
424 }); |
|
425 var providerChangeNeeded = false; |
|
426 if (!is_absolute && rtmp) api.__set('rtmp', rtmp.url || rtmp); |
|
427 else { |
|
428 var oldRtmp = api.__get('rtmp'); |
|
429 providerChangeNeeded = !!oldRtmp; |
|
430 api.__set('rtmp', null); |
|
431 } |
|
432 api.__play(url, providerChangeNeeded || video.rtmp && video.rtmp !== conf.rtmp); |
|
433 |
|
434 } else { |
|
435 |
|
436 callbackId = "fpCallback" + ("" + Math.random()).slice(3, 15); |
|
437 |
|
438 var opts = { |
|
439 hostname: conf.embedded ? common.hostname(conf.hostname) : common.hostname(location.hostname), |
|
440 url: url, |
|
441 callback: callbackId |
|
442 }; |
|
443 if (root.getAttribute('data-origin')) { |
|
444 opts.origin = root.getAttribute('data-origin'); |
|
445 } |
|
446 |
|
447 // optional conf |
|
448 ['proxy', 'key', 'autoplay', 'preload', 'subscribe', 'live', 'loop', 'debug', 'splash', 'poster', 'rtmpt'].forEach(function(key) { |
|
449 if (conf.hasOwnProperty(key)) opts[key] = conf[key]; |
|
450 if (video.hasOwnProperty(key)) opts[key] = video[key]; |
|
451 if ((conf.rtmp || {}).hasOwnProperty(key)) opts[key] = (conf.rtmp || {})[key]; |
|
452 if ((video.rtmp || {}).hasOwnProperty(key)) opts[key] = (video.rtmp || {})[key]; |
|
453 }); |
|
454 if (conf.rtmp) opts.rtmp = conf.rtmp.url || conf.rtmp; |
|
455 if (video.rtmp) opts.rtmp = video.rtmp.url || video.rtmp; |
|
456 Object.keys(video.flashls || {}).forEach(function(key) { |
|
457 var val = video.flashls[key]; |
|
458 opts['hls_' + key] = val; |
|
459 }); |
|
460 // bufferTime might be 0 |
|
461 if (conf.bufferTime !== undefined) opts.bufferTime = conf.bufferTime; |
|
462 |
|
463 if (is_absolute) delete opts.rtmp; |
|
464 |
|
465 // issues #376 |
|
466 if (opts.rtmp) { |
|
467 opts.rtmp = escapeURL(opts.rtmp); |
|
468 } |
|
469 |
|
470 // issue #733 |
|
471 var bgColor = common.css(root, 'background-color') ||'', bg; |
|
472 if (bgColor.indexOf('rgb') === 0) { |
|
473 bg = toHex(bgColor); |
|
474 } else if (bgColor.indexOf('#') === 0) { |
|
475 bg = toLongHex(bgColor); |
|
476 } |
|
477 |
|
478 // issues #387 |
|
479 opts.initialVolume = player.volumeLevel; |
|
480 |
|
481 var swfUrl = isHLS(video) ? conf.swfHls : conf.swf; |
|
482 |
|
483 api = embed(swfUrl, opts, conf.wmode, bg)[0]; |
|
484 |
|
485 var container = common.find('.fp-player', root)[0]; |
|
486 |
|
487 common.prepend(container, api); |
|
488 |
|
489 // throw error if no loading occurs |
|
490 setTimeout(function() { |
|
491 try { |
|
492 if (!api.PercentLoaded()) { |
|
493 return player.trigger("error", [player, { code: 7, url: conf.swf }]); |
|
494 } |
|
495 } catch (e) {} |
|
496 }, 5000); |
|
497 |
|
498 // detect disabled flash |
|
499 setTimeout(function() { |
|
500 if (typeof api.PercentLoaded === 'undefined') { |
|
501 player.trigger('flashdisabled', [player]); |
|
502 } |
|
503 }, 1000); |
|
504 |
|
505 api.pollInterval = setInterval(function () { |
|
506 if (!api) return; |
|
507 var status = api.__status ? api.__status() : null; |
|
508 |
|
509 if (!status) return; |
|
510 |
|
511 if (player.playing && status.time && status.time !== player.video.time) player.trigger("progress", [player, status.time]); |
|
512 |
|
513 video.buffer = status.buffer / video.bytes * video.duration; |
|
514 player.trigger("buffer", [player, video.buffer]); |
|
515 if (!video.buffered && status.time > 0) { |
|
516 video.buffered = true; |
|
517 player.trigger("buffered", [player]); |
|
518 } |
|
519 |
|
520 }, 250); |
|
521 |
|
522 // listen |
|
523 window[callbackId] = function(type, arg) { |
|
524 var video = loadVideo; |
|
525 |
|
526 if (conf.debug) { |
|
527 if (type.indexOf('debug') === 0 && arg && arg.length) { |
|
528 console.log.apply(console, ['-- ' + type].concat(arg)); |
|
529 } |
|
530 else console.log("--", type, arg); |
|
531 } |
|
532 |
|
533 var event = { |
|
534 type: type |
|
535 }; |
|
536 |
|
537 switch (type) { |
|
538 |
|
539 // RTMP sends a lot of finish events in vain |
|
540 // case "finish": if (conf.rtmp) return; |
|
541 case "ready": arg = extend(video, arg); break; |
|
542 case "click": event.flash = true; break; |
|
543 case "keydown": event.which = arg; break; |
|
544 case "seek": video.time = arg; break; |
|
545 case "status": |
|
546 player.trigger("progress", [player, arg.time]); |
|
547 |
|
548 if (arg.buffer < video.bytes && !video.buffered) { |
|
549 video.buffer = arg.buffer / video.bytes * video.duration; |
|
550 player.trigger("buffer", video.buffer); |
|
551 } else if (!video.buffered) { |
|
552 video.buffered = true; |
|
553 player.trigger("buffered"); |
|
554 } |
|
555 |
|
556 break; |
|
557 } |
|
558 if (type === 'click' || type === 'keydown') { |
|
559 event.target = root; |
|
560 bean.fire(root, type, [event]); |
|
561 } |
|
562 else if (type != 'buffered' && type !== 'unload') { |
|
563 // add some delay so that player is truly ready after an event |
|
564 setTimeout(function() { player.trigger(event, [player, arg]); }, 1); |
|
565 } else if (type === 'unload') { |
|
566 player.trigger(event, [player, arg]); |
|
567 } |
|
568 |
|
569 }; |
|
570 |
|
571 } |
|
572 |
|
573 }, |
|
574 |
|
575 // not supported yet |
|
576 speed: common.noop, |
|
577 |
|
578 |
|
579 unload: function() { |
|
580 if (api && api.__unload) api.__unload(); |
|
581 try { |
|
582 if (callbackId && window[callbackId])delete window[callbackId]; |
|
583 } catch (e) {} |
|
584 common.find("object", root).forEach(common.removeNode); |
|
585 api = 0; |
|
586 player.off('.flashengine'); |
|
587 clearInterval(api.pollInterval); |
|
588 } |
|
589 |
|
590 }; |
|
591 |
|
592 ['pause','resume','seek','volume'].forEach(function(name) { |
|
593 |
|
594 engine[name] = function(arg) { |
|
595 try { |
|
596 if (player.ready) { |
|
597 |
|
598 if (name == 'seek' && player.video.time && !player.paused) { |
|
599 player.trigger("beforeseek"); |
|
600 } |
|
601 |
|
602 if (arg === undefined) { |
|
603 api["__" + name](); |
|
604 |
|
605 } else { |
|
606 api["__" + name](arg); |
|
607 } |
|
608 |
|
609 } |
|
610 } catch (e) { |
|
611 if (typeof api["__" + name] === 'undefined') { //flash lost it's methods |
|
612 return player.trigger('flashdisabled', [player]); |
|
613 } |
|
614 throw e; |
|
615 } |
|
616 }; |
|
617 |
|
618 }); |
|
619 |
|
620 function toHex(bg) { |
|
621 function hex(x) { |
|
622 return ("0" + parseInt(x).toString(16)).slice(-2); |
|
623 } |
|
624 |
|
625 bg = bg.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); |
|
626 if (!bg) return; |
|
627 |
|
628 return '#' + hex(bg[1]) + hex(bg[2]) + hex(bg[3]); |
|
629 } |
|
630 |
|
631 function toLongHex(bg) { |
|
632 if (bg.length === 7) return bg; |
|
633 var a = bg.split('').slice(1); |
|
634 return '#' + a.map(function(i) { |
|
635 return i + i; |
|
636 }).join(''); |
|
637 } |
|
638 |
|
639 function isHLS(video) { |
|
640 return /application\/x-mpegurl/i.test(video.type); |
|
641 } |
|
642 |
|
643 return engine; |
|
644 |
|
645 }; |
|
646 |
|
647 |
|
648 engineImpl.engineName = 'flash'; |
|
649 engineImpl.canPlay = function(type, conf) { |
|
650 return flowplayer.support.flashVideo && /video\/(mp4|flash|flv)/i.test(type) || flowplayer.support.flashVideo && conf.swfHls && /mpegurl/i.test(type); |
|
651 }; |
|
652 flowplayer.engines.push(engineImpl); |
|
653 |
|
654 },{"../common":1,"../flowplayer":18,"./embed":2,"bean":20,"extend-object":26}],4:[function(_dereq_,module,exports){ |
|
655 'use strict'; |
|
656 var flowplayer = _dereq_('../flowplayer'), |
|
657 bean = _dereq_('bean'), |
|
658 ClassList = _dereq_('class-list'), |
|
659 extend = _dereq_('extend-object'), |
|
660 common = _dereq_('../common'); |
|
661 var VIDEO = document.createElement('video'); |
|
662 |
|
663 // HTML5 --> Flowplayer event |
|
664 var EVENTS = { |
|
665 |
|
666 // fired |
|
667 ended: 'finish', |
|
668 pause: 'pause', |
|
669 play: 'resume', |
|
670 progress: 'buffer', |
|
671 timeupdate: 'progress', |
|
672 volumechange: 'volume', |
|
673 ratechange: 'speed', |
|
674 //seeking: 'beforeseek', |
|
675 seeked: 'seek', |
|
676 // abort: 'resume', |
|
677 |
|
678 // not fired |
|
679 loadeddata: 'ready', |
|
680 // loadedmetadata: 0, |
|
681 // canplay: 0, |
|
682 |
|
683 // error events |
|
684 // load: 0, |
|
685 // emptied: 0, |
|
686 // empty: 0, |
|
687 error: 'error', |
|
688 dataunavailable: 'error', |
|
689 webkitendfullscreen: !flowplayer.support.inlineVideo && 'unload' |
|
690 |
|
691 }; |
|
692 |
|
693 function round(val, per) { |
|
694 per = per || 100; |
|
695 return Math.round(val * per) / per; |
|
696 } |
|
697 |
|
698 function getType(type) { |
|
699 return /mpegurl/i.test(type) ? "application/x-mpegurl" : type; |
|
700 } |
|
701 |
|
702 function canPlay(type) { |
|
703 if (!/^(video|application)/i.test(type)) |
|
704 type = getType(type); |
|
705 return !!VIDEO.canPlayType(type).replace("no", ''); |
|
706 } |
|
707 |
|
708 function findFromSourcesByType(sources, type) { |
|
709 var arr = sources.filter(function(s) { |
|
710 return s.type === type; |
|
711 }); |
|
712 return arr.length ? arr[0] : null; |
|
713 } |
|
714 |
|
715 var videoTagCache; |
|
716 var createVideoTag = function(video, autoplay, preload, useCache) { |
|
717 if (typeof autoplay === 'undefined') autoplay = true; |
|
718 if (typeof preload === 'undefined') preload = 'none'; |
|
719 if (typeof useCache === 'undefined') useCache = true; |
|
720 if (useCache && videoTagCache) { |
|
721 videoTagCache.type = getType(video.type); |
|
722 videoTagCache.src = video.src; |
|
723 return videoTagCache; |
|
724 } |
|
725 var el = document.createElement('video'); |
|
726 el.src = video.src; |
|
727 el.type = getType(video.type); |
|
728 el.className = 'fp-engine'; |
|
729 el.autoplay = autoplay ? 'autoplay' : false; |
|
730 el.preload = preload; |
|
731 el.setAttribute('x-webkit-airplay', 'allow'); |
|
732 if (useCache) videoTagCache = el; |
|
733 return el; |
|
734 }; |
|
735 |
|
736 var engine; |
|
737 |
|
738 engine = function(player, root) { |
|
739 |
|
740 var api = common.findDirect('video', root)[0] || common.find('.fp-player > video', root)[0], |
|
741 support = flowplayer.support, |
|
742 track = common.find("track", api)[0], |
|
743 conf = player.conf, |
|
744 self, |
|
745 timer, |
|
746 volumeLevel; |
|
747 /*jshint -W093 */ |
|
748 return self = { |
|
749 engineName: engine.engineName, |
|
750 |
|
751 pick: function(sources) { |
|
752 if (support.video) { |
|
753 if (conf.videoTypePreference) { |
|
754 var mp4source = findFromSourcesByType(sources, conf.videoTypePreference); |
|
755 if (mp4source) return mp4source; |
|
756 } |
|
757 |
|
758 for (var i = 0, source; i < sources.length; i++) { |
|
759 if (canPlay(sources[i].type)) return sources[i]; |
|
760 } |
|
761 } |
|
762 }, |
|
763 |
|
764 load: function(video) { |
|
765 var created = false, container = common.find('.fp-player', root)[0], reload = false; |
|
766 if (conf.splash && !api) { |
|
767 api = createVideoTag(video); |
|
768 common.prepend(container, api); |
|
769 created = true; |
|
770 } else if (!api) { |
|
771 api = createVideoTag(video, !!video.autoplay || !!conf.autoplay, conf.clip.preload || 'metadata', false); |
|
772 common.prepend(container, api); |
|
773 created = true; |
|
774 } else { |
|
775 ClassList(api).add('fp-engine'); |
|
776 common.find('source,track', api).forEach(common.removeNode); |
|
777 if (!player.conf.nativesubtitles) common.attr(api, 'crossorigin', false); |
|
778 reload = api.src === video.src; |
|
779 } |
|
780 if (!support.inlineVideo) { |
|
781 common.css(api, { |
|
782 position: 'absolute', |
|
783 top: '-9999em' |
|
784 }); |
|
785 } |
|
786 //TODO subtitles support |
|
787 |
|
788 // IE does not fire delegated timeupdate events |
|
789 bean.off(api, 'timeupdate', common.noop); |
|
790 bean.on(api, 'timeupdate', common.noop); |
|
791 |
|
792 common.prop(api, 'loop', !!(video.loop || conf.loop)); |
|
793 |
|
794 if (typeof volumeLevel !== 'undefined') { |
|
795 api.volume = volumeLevel; |
|
796 } |
|
797 |
|
798 if (player.video.src && video.src != player.video.src || video.index) common.attr(api, 'autoplay', 'autoplay'); |
|
799 api.src = video.src; |
|
800 api.type = video.type; |
|
801 |
|
802 listen(api, common.find("source", api).concat(api), video); |
|
803 |
|
804 // iPad (+others?) demands load() |
|
805 if (conf.clip.preload != 'none' && video.type != "mpegurl" || !support.zeropreload || !support.dataload) api.load(); |
|
806 if (created || reload) api.load(); |
|
807 if (api.paused && (video.autoplay || conf.autoplay)) api.play(); |
|
808 }, |
|
809 |
|
810 pause: function() { |
|
811 api.pause(); |
|
812 }, |
|
813 |
|
814 resume: function() { |
|
815 api.play(); |
|
816 }, |
|
817 |
|
818 speed: function(val) { |
|
819 api.playbackRate = val; |
|
820 }, |
|
821 |
|
822 seek: function(time) { |
|
823 try { |
|
824 var pausedState = player.paused; |
|
825 api.currentTime = time; |
|
826 if (pausedState) api.pause(); |
|
827 } catch (ignored) {} |
|
828 }, |
|
829 |
|
830 volume: function(level) { |
|
831 volumeLevel = level; |
|
832 if (api) { |
|
833 api.volume = level; |
|
834 } |
|
835 }, |
|
836 |
|
837 unload: function() { |
|
838 common.find('video.fp-engine', root).forEach(common.removeNode); |
|
839 if (!support.cachedVideoTag) videoTagCache = null; |
|
840 timer = clearInterval(timer); |
|
841 api = 0; |
|
842 } |
|
843 |
|
844 }; |
|
845 |
|
846 function listen(api, sources, video) { |
|
847 // listen only once |
|
848 var instanceId = root.getAttribute('data-flowplayer-instance-id'); |
|
849 |
|
850 if (api.listeners && api.listeners.hasOwnProperty(instanceId)) { |
|
851 api.listeners[instanceId] = video; |
|
852 return; |
|
853 } |
|
854 (api.listeners || (api.listeners = {}))[instanceId] = video; |
|
855 |
|
856 bean.on(sources, 'error', function(e) { |
|
857 try { |
|
858 if (canPlay(e.target.getAttribute('type'))) { |
|
859 player.trigger("error", [player, { code: 4, video: extend(video, {src: api.src, url: api.src}) }]); |
|
860 } |
|
861 } catch (er) { |
|
862 // Most likely: https://bugzilla.mozilla.org/show_bug.cgi?id=208427 |
|
863 } |
|
864 }); |
|
865 |
|
866 player.on('shutdown', function() { |
|
867 bean.off(sources); |
|
868 }); |
|
869 |
|
870 Object.keys(EVENTS).forEach(function(type) { |
|
871 var flow = EVENTS[type]; |
|
872 if (!flow) return; |
|
873 root.addEventListener(type, function(e) { |
|
874 video = api.listeners[instanceId]; |
|
875 if (!e.target || !ClassList(e.target).contains('fp-engine')) return; |
|
876 |
|
877 if (conf.debug && !/progress/.test(flow)) console.log(type, "->", flow, e); |
|
878 |
|
879 // no events if player not ready |
|
880 if (!player.ready && !/ready|error/.test(flow) || !flow || !common.find('video', root).length) { return; } |
|
881 |
|
882 var arg, vtype; |
|
883 |
|
884 if (flow === 'unload') { //Call player unload |
|
885 player.unload(); |
|
886 return; |
|
887 } |
|
888 |
|
889 var triggerEvent = function() { |
|
890 player.trigger(flow, [player, arg]); |
|
891 }; |
|
892 |
|
893 switch (flow) { |
|
894 |
|
895 case "ready": |
|
896 |
|
897 arg = extend(video, { |
|
898 duration: api.duration, |
|
899 width: api.videoWidth, |
|
900 height: api.videoHeight, |
|
901 url: api.currentSrc, |
|
902 src: api.currentSrc |
|
903 }); |
|
904 |
|
905 try { |
|
906 arg.seekable = !conf.live && /mpegurl/i.test(video ? (video.type || '') : '') && api.duration || api.seekable && api.seekable.end(null); |
|
907 |
|
908 } catch (ignored) {} |
|
909 |
|
910 // buffer |
|
911 timer = timer || setInterval(function() { |
|
912 |
|
913 try { |
|
914 arg.buffer = api.buffered.end(null); |
|
915 |
|
916 } catch (ignored) {} |
|
917 |
|
918 if (arg.buffer) { |
|
919 if (round(arg.buffer, 1000) < round(arg.duration, 1000) && !arg.buffered) { |
|
920 player.trigger("buffer", e); |
|
921 |
|
922 } else if (!arg.buffered) { |
|
923 arg.buffered = true; |
|
924 player.trigger("buffer", e).trigger("buffered", e); |
|
925 clearInterval(timer); |
|
926 timer = 0; |
|
927 } |
|
928 } |
|
929 |
|
930 }, 250); |
|
931 |
|
932 if (!conf.live && !arg.duration && !support.hlsDuration && type === "loadeddata") { |
|
933 var durationChanged = function() { |
|
934 arg.duration = api.duration; |
|
935 try { |
|
936 arg.seekable = api.seekable && api.seekable.end(null); |
|
937 |
|
938 } catch (ignored) {} |
|
939 triggerEvent(); |
|
940 api.removeEventListener('durationchange', durationChanged); |
|
941 ClassList(root).remove('is-live'); |
|
942 }; |
|
943 api.addEventListener('durationchange', durationChanged); |
|
944 |
|
945 // Ugly hack to handle broken Android devices |
|
946 var timeUpdated = function() { |
|
947 if (!player.ready && !api.duration) { // No duration even though the video already plays |
|
948 arg.duration = 0; |
|
949 ClassList(root).add('is-live'); // Make UI believe it's live |
|
950 triggerEvent(); |
|
951 } |
|
952 api.removeEventListener('timeupdate', timeUpdated); |
|
953 }; |
|
954 api.addEventListener('timeupdate', timeUpdated); |
|
955 return; |
|
956 } |
|
957 |
|
958 break; |
|
959 |
|
960 case "progress": case "seek": |
|
961 |
|
962 var dur = player.video.duration; |
|
963 |
|
964 if (api.currentTime > 0 || player.live) { |
|
965 arg = Math.max(api.currentTime, 0); |
|
966 |
|
967 } else if (flow == 'progress') { |
|
968 return; |
|
969 } |
|
970 break; |
|
971 |
|
972 |
|
973 case "speed": |
|
974 arg = round(api.playbackRate); |
|
975 break; |
|
976 |
|
977 case "volume": |
|
978 arg = round(api.volume); |
|
979 break; |
|
980 |
|
981 case "error": |
|
982 try { |
|
983 arg = (e.srcElement || e.originalTarget).error; |
|
984 arg.video = extend(video, {src: api.src, url: api.src}); |
|
985 } catch (er) { |
|
986 // Most likely https://bugzilla.mozilla.org/show_bug.cgi?id=208427 |
|
987 return; |
|
988 } |
|
989 } |
|
990 |
|
991 triggerEvent(); |
|
992 |
|
993 |
|
994 }, true); |
|
995 |
|
996 }); |
|
997 |
|
998 } |
|
999 |
|
1000 }; |
|
1001 |
|
1002 |
|
1003 engine.canPlay = function(type) { |
|
1004 return flowplayer.support.video && canPlay(type); |
|
1005 }; |
|
1006 |
|
1007 engine.engineName = 'html5'; |
|
1008 |
|
1009 flowplayer.engines.push(engine); |
|
1010 |
|
1011 },{"../common":1,"../flowplayer":18,"bean":20,"class-list":22,"extend-object":26}],5:[function(_dereq_,module,exports){ |
|
1012 'use strict'; |
|
1013 /* global _gat */ |
|
1014 var flowplayer = _dereq_('../flowplayer'), |
|
1015 TYPE_RE = _dereq_('./resolve').TYPE_RE, |
|
1016 scriptjs = _dereq_('scriptjs'), |
|
1017 bean = _dereq_('bean'); |
|
1018 flowplayer(function(player, root) { |
|
1019 |
|
1020 var id = player.conf.analytics, time = 0, last = 0, timer; |
|
1021 |
|
1022 if (id) { |
|
1023 |
|
1024 // load Analytics script if needed |
|
1025 if (typeof _gat == 'undefined') scriptjs("//google-analytics.com/ga.js"); |
|
1026 |
|
1027 var getTracker = function() { |
|
1028 var tracker = _gat._getTracker(id); |
|
1029 tracker._setAllowLinker(true); |
|
1030 return tracker; |
|
1031 }; |
|
1032 |
|
1033 var track = function track(e, api, video) { |
|
1034 |
|
1035 video = video || player.video; |
|
1036 |
|
1037 if (time && typeof _gat != 'undefined') { |
|
1038 var tracker = getTracker(); |
|
1039 |
|
1040 |
|
1041 // http://code.google.com/apis/analytics/docs/tracking/eventTrackerGuide.html |
|
1042 tracker._trackEvent( |
|
1043 "Video / Seconds played", |
|
1044 player.engine.engineName + "/" + video.type, |
|
1045 video.title || root.getAttribute("title") || video.src.split("/").slice(-1)[0].replace(TYPE_RE, ''), |
|
1046 Math.round(time / 1000) |
|
1047 ); |
|
1048 time = 0; |
|
1049 if (timer) { |
|
1050 clearTimeout(timer); |
|
1051 timer = null; |
|
1052 } |
|
1053 } |
|
1054 |
|
1055 }; |
|
1056 |
|
1057 player.bind("load unload", track).bind("progress", function() { |
|
1058 |
|
1059 if (!player.seeking) { |
|
1060 time += last ? (+new Date() - last) : 0; |
|
1061 last = +new Date(); |
|
1062 } |
|
1063 |
|
1064 if (!timer) { |
|
1065 timer = setTimeout(function() { |
|
1066 timer = null; |
|
1067 var tracker = getTracker(); |
|
1068 tracker._trackEvent('Flowplayer heartbeat', 'Heartbeat', '', 0, true); |
|
1069 }, 10*60*1000); // heartbeat every 10 minutes |
|
1070 } |
|
1071 |
|
1072 }).bind("pause", function() { |
|
1073 last = 0; |
|
1074 }); |
|
1075 |
|
1076 player.bind('shutdown', function() { |
|
1077 bean.off(window, 'unload', track); |
|
1078 }); |
|
1079 |
|
1080 bean.on(window, 'unload', track); |
|
1081 |
|
1082 } |
|
1083 |
|
1084 }); |
|
1085 |
|
1086 },{"../flowplayer":18,"./resolve":13,"bean":20,"scriptjs":29}],6:[function(_dereq_,module,exports){ |
|
1087 'use strict'; |
|
1088 var flowplayer = _dereq_('../flowplayer'), |
|
1089 ClassList = _dereq_('class-list'), |
|
1090 common = _dereq_('../common'), |
|
1091 bean = _dereq_('bean'); |
|
1092 |
|
1093 flowplayer(function(player, root) { |
|
1094 |
|
1095 var CUE_RE = / ?cue\d+ ?/; |
|
1096 |
|
1097 var lastTime = 0, cuepointsDisabled = false; |
|
1098 |
|
1099 function setClass(index) { |
|
1100 root.className = root.className.replace(CUE_RE, " "); |
|
1101 if (index >= 0) ClassList(root).add('cue' + index); |
|
1102 } |
|
1103 |
|
1104 var segments = {}, lastFiredSegment = -0.125; |
|
1105 |
|
1106 var fire = function(cue) { |
|
1107 var idx = player.cuepoints.indexOf(cue); |
|
1108 if (!isNaN(cue)) cue = { time: cue }; |
|
1109 cue.index = idx; |
|
1110 setClass(idx); |
|
1111 player.trigger('cuepoint', [player, cue]); |
|
1112 }; |
|
1113 |
|
1114 player.on("progress", function(e, api, time) { |
|
1115 if (cuepointsDisabled) return; |
|
1116 var segment = segmentForCue(time); |
|
1117 while (lastFiredSegment < segment) { |
|
1118 lastFiredSegment += 0.125; |
|
1119 if (!segments[lastFiredSegment]) continue; |
|
1120 segments[lastFiredSegment].forEach(fire); |
|
1121 } |
|
1122 |
|
1123 }).on("unload", setClass) |
|
1124 .on('beforeseek', function() { |
|
1125 cuepointsDisabled = true; |
|
1126 }).on("seek", function(ev, api, time) { |
|
1127 setClass(); |
|
1128 lastFiredSegment = segmentForCue(time || 0) - 0.125; |
|
1129 cuepointsDisabled = false; |
|
1130 if (!time && segments[0]) segments[0].forEach(fire); |
|
1131 }).on('ready', function(e, api, video) { |
|
1132 lastFiredSegment = -0.125; |
|
1133 var cues = video.cuepoints || player.conf.cuepoints || []; |
|
1134 player.setCuepoints(cues); |
|
1135 }).on('finish', function() { |
|
1136 lastFiredSegment = -0.125; |
|
1137 }); |
|
1138 if (player.conf.generate_cuepoints) { |
|
1139 |
|
1140 player.bind("load", function() { |
|
1141 |
|
1142 // clean up cuepoint elements of previous playlist items |
|
1143 common.find('.fp-cuepoint', root).forEach(common.removeNode); |
|
1144 |
|
1145 }); |
|
1146 } |
|
1147 |
|
1148 /** |
|
1149 * API |
|
1150 */ |
|
1151 player.setCuepoints = function(cues) { |
|
1152 player.cuepoints = []; |
|
1153 segments = {}; |
|
1154 cues.forEach(player.addCuepoint); |
|
1155 return player; |
|
1156 }; |
|
1157 player.addCuepoint = function(cue) { |
|
1158 if (!player.cuepoints) player.cuepoints = []; |
|
1159 var segment = segmentForCue(cue); |
|
1160 if (!segments[segment]) segments[segment] = []; |
|
1161 segments[segment].push(cue); |
|
1162 player.cuepoints.push(cue); |
|
1163 |
|
1164 if (player.conf.generate_cuepoints && cue.visible !== false) { |
|
1165 var duration = player.video.duration, |
|
1166 timeline = common.find('.fp-timeline', root)[0]; |
|
1167 common.css(timeline, "overflow", "visible"); |
|
1168 |
|
1169 var time = cue.time || cue; |
|
1170 if (time < 0) time = duration + cue; |
|
1171 |
|
1172 var el = common.createElement('a', {className: 'fp-cuepoint fp-cuepoint' + (player.cuepoints.length - 1)}); |
|
1173 common.css(el, "left", (time / duration * 100) + "%"); |
|
1174 |
|
1175 timeline.appendChild(el); |
|
1176 bean.on(el, 'mousedown', function(e) { |
|
1177 e.preventDefault(); |
|
1178 player.seek(time); |
|
1179 |
|
1180 // preventDefault() doesn't work |
|
1181 return false; |
|
1182 }); |
|
1183 } |
|
1184 return player; |
|
1185 }; |
|
1186 |
|
1187 player.removeCuepoint = function(cue) { |
|
1188 var idx = player.cuepoints.indexOf(cue), |
|
1189 segment = segmentForCue(cue); |
|
1190 if (idx === -1) return; |
|
1191 player.cuepoints = player.cuepoints.slice(0, idx).concat(player.cuepoints.slice(idx+1)); |
|
1192 |
|
1193 var sIdx = segments[segment].indexOf(cue); |
|
1194 if (sIdx === -1) return; |
|
1195 segments[segment] = segments[segment].slice(0, sIdx).concat(segments[segment].slice(sIdx+1)); |
|
1196 return player; |
|
1197 }; |
|
1198 |
|
1199 function segmentForCue(cue) { |
|
1200 var time = cue && !isNaN(cue.time) ? cue.time : cue; |
|
1201 if (time < 0) time = player.video.duration + time; |
|
1202 return Math.round(time/0.125)*0.125; |
|
1203 } |
|
1204 |
|
1205 }); |
|
1206 |
|
1207 },{"../common":1,"../flowplayer":18,"bean":20,"class-list":22}],7:[function(_dereq_,module,exports){ |
|
1208 'use strict'; |
|
1209 var flowplayer = _dereq_('../flowplayer'), |
|
1210 bean = _dereq_('bean'), |
|
1211 common = _dereq_('../common'), |
|
1212 isObject = _dereq_('is-object'), |
|
1213 extend = _dereq_('extend-object'), |
|
1214 ClassList = _dereq_('class-list'); |
|
1215 |
|
1216 |
|
1217 |
|
1218 flowplayer(function(player, root) { |
|
1219 |
|
1220 // no embedding |
|
1221 if (player.conf.embed === false) return; |
|
1222 |
|
1223 var conf = player.conf, |
|
1224 ui = common.find('.fp-ui', root)[0], |
|
1225 trigger = common.createElement('a', { "class": "fp-embed", title: 'Copy to your site'}), |
|
1226 target = common.createElement('div',{ 'class': 'fp-embed-code'}, '<label>Paste this HTML code on your site to embed.</label><textarea></textarea>'), |
|
1227 area = common.find("textarea", target)[0]; |
|
1228 |
|
1229 ui.appendChild(trigger); |
|
1230 ui.appendChild(target); |
|
1231 |
|
1232 player.embedCode = function() { |
|
1233 var embedConf = player.conf.embed || {}, |
|
1234 video = player.video; |
|
1235 |
|
1236 if (embedConf.iframe) { |
|
1237 var src = player.conf.embed.iframe, |
|
1238 width = embedConf.width || video.width || common.width(root), |
|
1239 height = embedConf.height || video.height || common.height(root); |
|
1240 return '<iframe src="' + player.conf.embed.iframe + '" frameBorder="0" allowfullscreen width="' + width + '" height="' + height + '"></iframe>'; |
|
1241 } |
|
1242 var props = ['ratio', 'rtmp', 'live', 'bufferTime', 'origin', 'analytics', 'key', 'subscribe', 'swf', 'swfHls', 'embed', 'adaptiveRatio', 'logo']; |
|
1243 if (embedConf.playlist) props.push('playlist'); |
|
1244 var c = common.pick(player.conf, props); |
|
1245 if (c.logo) c.logo = common.createElement('img', {src: c.logo}).src; |
|
1246 if (!embedConf.playlist || !player.conf.playlist.length) c.clip = extend({}, player.conf.clip, common.pick(player.video, ['sources'])); |
|
1247 var script = "var w=window,d=document,e;w._fpes||(w._fpes=[],w.addEventListener(\"load\",function(){var s=d.createElement(\"script\");s.src=\"//embed.flowplayer.org/6.0.3/embed.min.js\",d.body.appendChild(s)})),e=[].slice.call(d.getElementsByTagName(\"script\"),-1)[0].parentNode,w._fpes.push({e:e,l:\"$library\",c:$conf});\n".replace('$conf', JSON.stringify(c)).replace('$library', embedConf.library || ''); |
|
1248 |
|
1249 return '<a href="$href">Watch video!\n<script>$script</script></a>'.replace('$href', player.conf.origin || window.location.href).replace('$script', script); |
|
1250 |
|
1251 }; |
|
1252 fptip(root, ".fp-embed", "is-embedding"); |
|
1253 |
|
1254 bean.on(root, 'click', '.fp-embed-code textarea', function() { |
|
1255 area.select(); |
|
1256 }); |
|
1257 |
|
1258 bean.on(root, 'click', '.fp-embed', function() { |
|
1259 area.textContent = player.embedCode().replace(/(\r\n|\n|\r)/gm,""); |
|
1260 area.focus(); |
|
1261 area.select(); |
|
1262 }); |
|
1263 |
|
1264 }); |
|
1265 |
|
1266 var fptip = function(root, trigger, active) { |
|
1267 |
|
1268 function close() { |
|
1269 rootClasses.remove(active); |
|
1270 bean.off(document, '.st'); |
|
1271 } |
|
1272 |
|
1273 var rootClasses = ClassList(root); |
|
1274 |
|
1275 bean.on(root, 'click', trigger || 'a', function(e) { |
|
1276 e.preventDefault(); |
|
1277 |
|
1278 rootClasses.toggle(active); |
|
1279 |
|
1280 if (rootClasses.contains(active)) { |
|
1281 |
|
1282 bean.on(document, 'keydown.st', function(e) { |
|
1283 if (e.which == 27) close(); |
|
1284 }); |
|
1285 bean.on(document, 'click.st', function(e) { |
|
1286 if (!common.hasParent(e.target, '.' + active)) close(); |
|
1287 }); |
|
1288 } |
|
1289 }); |
|
1290 }; |
|
1291 |
|
1292 |
|
1293 },{"../common":1,"../flowplayer":18,"bean":20,"class-list":22,"extend-object":26,"is-object":28}],8:[function(_dereq_,module,exports){ |
|
1294 'use strict'; |
|
1295 /* global jQuery */ |
|
1296 /** |
|
1297 * Mimimal jQuery-like event emitter implementation |
|
1298 */ |
|
1299 module.exports = function(obj, elem) { |
|
1300 if (!elem) elem = document.createElement('div'); //In this case we always want to trigger (Custom)Events on dom element |
|
1301 var handlers = {}, eventArguments = {}; |
|
1302 |
|
1303 var listenEvent = function(type, hndlr, disposable) { |
|
1304 var actualEvent = type.split('.')[0]; //Strip namespace |
|
1305 var internalHandler = function(ev) { |
|
1306 if (disposable) { |
|
1307 elem.removeEventListener(actualEvent, internalHandler); |
|
1308 handlers[type].splice(handlers[type].indexOf(internalHandler), 1); |
|
1309 } |
|
1310 var args = [ev].concat(eventArguments[ev.timeStamp + ev.type] || []); |
|
1311 if (hndlr) hndlr.apply(undefined, args); |
|
1312 }; |
|
1313 elem.addEventListener(actualEvent, internalHandler); |
|
1314 |
|
1315 //Store handlers for unbinding |
|
1316 if (!handlers[type]) handlers[type] = []; |
|
1317 handlers[type].push(internalHandler); |
|
1318 }; |
|
1319 |
|
1320 obj.on = obj.bind = function(typ, hndlr) { |
|
1321 var types = typ.split(' '); |
|
1322 types.forEach(function(type) { |
|
1323 listenEvent(type, hndlr); |
|
1324 }); |
|
1325 return obj; //for chaining |
|
1326 }; |
|
1327 |
|
1328 obj.one = function(typ, hndlr) { |
|
1329 var types = typ.split(' '); |
|
1330 types.forEach(function(type) { |
|
1331 listenEvent(type, hndlr, true); |
|
1332 }); |
|
1333 return obj; |
|
1334 }; |
|
1335 |
|
1336 // Function to check if all items in toBeContained array are in the containing array |
|
1337 var containsAll = function(containing, toBeContained) { |
|
1338 return toBeContained.filter(function(i) { |
|
1339 return containing.indexOf(i) === -1; |
|
1340 }).length === 0; |
|
1341 }; |
|
1342 |
|
1343 |
|
1344 obj.off = obj.unbind = function(typ) { |
|
1345 var types = typ.split(' '); |
|
1346 types.forEach(function(type) { |
|
1347 var typeNameSpaces = type.split('.').slice(1), |
|
1348 actualType = type.split('.')[0]; |
|
1349 Object.keys(handlers).filter(function(t) { |
|
1350 var handlerNamespaces = t.split('.').slice(1); |
|
1351 return (!actualType || t.indexOf(actualType) === 0) && containsAll(handlerNamespaces, typeNameSpaces); |
|
1352 }).forEach(function(t) { |
|
1353 var registererHandlers = handlers[t], |
|
1354 actualEvent = t.split('.')[0]; |
|
1355 registererHandlers.forEach(function(hndlr) { |
|
1356 elem.removeEventListener(actualEvent, hndlr); |
|
1357 registererHandlers.splice(registererHandlers.indexOf(hndlr), 1); |
|
1358 }); |
|
1359 }); |
|
1360 }); |
|
1361 return obj; |
|
1362 }; |
|
1363 |
|
1364 obj.trigger = function(typ, args, returnEvent) { |
|
1365 if (!typ) return; |
|
1366 args = (args || []).length ? args || [] : [args]; |
|
1367 var event = document.createEvent('Event'), typStr; |
|
1368 typStr = typ.type || typ; |
|
1369 event.initEvent(typStr, false, true); |
|
1370 eventArguments[event.timeStamp + event.type] = args; |
|
1371 elem.dispatchEvent(event); |
|
1372 return returnEvent ? event : obj; |
|
1373 }; |
|
1374 }; |
|
1375 |
|
1376 |
|
1377 module.exports.EVENTS = [ |
|
1378 'beforeseek', |
|
1379 'disable', |
|
1380 'error', |
|
1381 'finish', |
|
1382 'fullscreen', |
|
1383 'fullscreen-exit', |
|
1384 'load', |
|
1385 'mute', |
|
1386 'pause', |
|
1387 'progress', |
|
1388 'ready', |
|
1389 'resume', |
|
1390 'seek', |
|
1391 'speed', |
|
1392 'stop', |
|
1393 'unload', |
|
1394 'volume', |
|
1395 'boot', |
|
1396 'shutdown' |
|
1397 ]; |
|
1398 |
|
1399 },{}],9:[function(_dereq_,module,exports){ |
|
1400 'use strict'; |
|
1401 var flowplayer = _dereq_('../flowplayer'), |
|
1402 bean = _dereq_('bean'), |
|
1403 ClassList = _dereq_('class-list'), |
|
1404 extend = _dereq_('extend-object'), |
|
1405 common = _dereq_('../common'), |
|
1406 VENDOR = flowplayer.support.browser.mozilla ? "moz": "webkit", |
|
1407 FS_ENTER = "fullscreen", |
|
1408 FS_EXIT = "fullscreen-exit", |
|
1409 FULL_PLAYER, |
|
1410 FS_SUPPORT = flowplayer.support.fullscreen, |
|
1411 FS_NATIVE_SUPPORT = typeof document.exitFullscreen == 'function', |
|
1412 ua = navigator.userAgent.toLowerCase(), |
|
1413 IS_SAFARI = /(safari)[ \/]([\w.]+)/.exec(ua) && !/(chrome)[ \/]([\w.]+)/.exec(ua); |
|
1414 |
|
1415 |
|
1416 // esc button |
|
1417 bean.on(document, "fullscreenchange.ffscr webkitfullscreenchange.ffscr mozfullscreenchange.ffscr MSFullscreenChange.ffscr", function(e) { |
|
1418 var el = document.webkitCurrentFullScreenElement || document.mozFullScreenElement || document.fullscreenElement || document.msFullscreenElement || e.target; |
|
1419 if (!FULL_PLAYER && (!el.parentNode || !el.parentNode.getAttribute('data-flowplayer-instance-id'))) return; |
|
1420 var player = FULL_PLAYER || flowplayer(el.parentNode); |
|
1421 if (el && !FULL_PLAYER) { |
|
1422 FULL_PLAYER = player.trigger(FS_ENTER, [el]); |
|
1423 } else { |
|
1424 FULL_PLAYER.trigger(FS_EXIT, [FULL_PLAYER]); |
|
1425 FULL_PLAYER = null; |
|
1426 } |
|
1427 }); |
|
1428 |
|
1429 flowplayer(function(player, root) { |
|
1430 |
|
1431 var wrapper = common.createElement('div', {className: 'fp-player'}); |
|
1432 Array.prototype.map.call(root.children, common.identity).forEach(function(el) { |
|
1433 if (common.matches(el, '.fp-ratio,script')) return; |
|
1434 wrapper.appendChild(el); |
|
1435 }); |
|
1436 root.appendChild(wrapper); |
|
1437 |
|
1438 if (!player.conf.fullscreen) return; |
|
1439 |
|
1440 var win = window, |
|
1441 scrollY, |
|
1442 scrollX, |
|
1443 rootClasses = ClassList(root); |
|
1444 |
|
1445 player.isFullscreen = false; |
|
1446 |
|
1447 player.fullscreen = function(flag) { |
|
1448 |
|
1449 if (player.disabled) return; |
|
1450 |
|
1451 if (flag === undefined) flag = !player.isFullscreen; |
|
1452 |
|
1453 if (flag) { |
|
1454 scrollY = win.scrollY; |
|
1455 scrollX = win.scrollX; |
|
1456 } |
|
1457 |
|
1458 if (FS_SUPPORT) { |
|
1459 |
|
1460 if (flag) { |
|
1461 ['requestFullScreen', 'webkitRequestFullScreen', 'mozRequestFullScreen', 'msRequestFullscreen'].forEach(function(fName) { |
|
1462 if (typeof wrapper[fName] === 'function') { |
|
1463 wrapper[fName](Element.ALLOW_KEYBOARD_INPUT); |
|
1464 if (IS_SAFARI && !document.webkitCurrentFullScreenElement && !document.mozFullScreenElement) { // Element.ALLOW_KEYBOARD_INPUT not allowed |
|
1465 wrapper[fName](); |
|
1466 } |
|
1467 return false; |
|
1468 } |
|
1469 }); |
|
1470 |
|
1471 } else { |
|
1472 ['exitFullscreen', 'webkitCancelFullScreen', 'mozCancelFullScreen', 'msExitFullscreen'].forEach(function(fName) { |
|
1473 if (typeof document[fName] === 'function') { |
|
1474 document[fName](); |
|
1475 return false; |
|
1476 } |
|
1477 }); |
|
1478 } |
|
1479 |
|
1480 } else { |
|
1481 player.trigger(flag ? FS_ENTER : FS_EXIT, [player]); |
|
1482 } |
|
1483 |
|
1484 return player; |
|
1485 }; |
|
1486 |
|
1487 var lastClick; |
|
1488 |
|
1489 player.on("mousedown.fs", function() { |
|
1490 if (+new Date() - lastClick < 150 && player.ready) player.fullscreen(); |
|
1491 lastClick = +new Date(); |
|
1492 }); |
|
1493 |
|
1494 player.on(FS_ENTER, function(e) { |
|
1495 rootClasses.add("is-fullscreen"); |
|
1496 if (!FS_SUPPORT) common.css(root, 'position', 'fixed'); |
|
1497 player.isFullscreen = true; |
|
1498 |
|
1499 }).on(FS_EXIT, function(e) { |
|
1500 var oldOpacity; |
|
1501 if (!FS_SUPPORT && player.engine === "html5") { |
|
1502 oldOpacity = root.css('opacity') || ''; |
|
1503 common.css(root, 'opacity', 0); |
|
1504 } |
|
1505 if (!FS_SUPPORT) common.css(root, 'position', ''); |
|
1506 rootClasses.remove("is-fullscreen"); |
|
1507 if (!FS_SUPPORT && player.engine === "html5") setTimeout(function() { root.css('opacity', oldOpacity); }); |
|
1508 player.isFullscreen = false; |
|
1509 win.scrollTo(scrollX, scrollY); |
|
1510 }).on('unload', function() { |
|
1511 if (player.isFullscreen) player.fullscreen(); |
|
1512 }); |
|
1513 |
|
1514 player.on('shutdown', function() { |
|
1515 bean.off(document, '.ffscr'); |
|
1516 FULL_PLAYER = null; |
|
1517 }); |
|
1518 |
|
1519 }); |
|
1520 |
|
1521 },{"../common":1,"../flowplayer":18,"bean":20,"class-list":22,"extend-object":26}],10:[function(_dereq_,module,exports){ |
|
1522 'use strict'; |
|
1523 var flowplayer = _dereq_('../flowplayer'), |
|
1524 bean = _dereq_('bean'), |
|
1525 focused, |
|
1526 focusedRoot, |
|
1527 IS_HELP = "is-help", |
|
1528 common = _dereq_('../common'), |
|
1529 ClassList = _dereq_('class-list'); |
|
1530 |
|
1531 // keyboard. single global listener |
|
1532 bean.on(document, "keydown.fp", function(e) { |
|
1533 |
|
1534 var el = focused, |
|
1535 metaKeyPressed = e.ctrlKey || e.metaKey || e.altKey, |
|
1536 key = e.which, |
|
1537 conf = el && el.conf, |
|
1538 focusedRootClasses = focusedRoot && ClassList(focusedRoot); |
|
1539 |
|
1540 if (!el || !conf.keyboard || el.disabled) return; |
|
1541 |
|
1542 // help dialog (shift key not truly required) |
|
1543 if ([63, 187, 191].indexOf(key) != -1) { |
|
1544 focusedRootClasses.toggle(IS_HELP); |
|
1545 return false; |
|
1546 } |
|
1547 |
|
1548 // close help / unload |
|
1549 if (key == 27 && focusedRootClasses.contains(IS_HELP)) { |
|
1550 focusedRootClasses.toggle(IS_HELP); |
|
1551 return false; |
|
1552 } |
|
1553 |
|
1554 if (!metaKeyPressed && el.ready) { |
|
1555 |
|
1556 e.preventDefault(); |
|
1557 |
|
1558 // slow motion / fast forward |
|
1559 if (e.shiftKey) { |
|
1560 if (key == 39) el.speed(true); |
|
1561 else if (key == 37) el.speed(false); |
|
1562 return; |
|
1563 } |
|
1564 |
|
1565 // 1, 2, 3, 4 .. |
|
1566 if (key < 58 && key > 47) return el.seekTo(key - 48); |
|
1567 |
|
1568 switch (key) { |
|
1569 case 38: case 75: el.volume(el.volumeLevel + 0.15); break; // volume up |
|
1570 case 40: case 74: el.volume(el.volumeLevel - 0.15); break; // volume down |
|
1571 case 39: case 76: el.seeking = true; el.seek(true); break; // forward |
|
1572 case 37: case 72: el.seeking = true; el.seek(false); break; // backward |
|
1573 case 190: el.seekTo(); break; // to last seek position |
|
1574 case 32: el.toggle(); break; // spacebar |
|
1575 case 70: if(conf.fullscreen) el.fullscreen(); break; // toggle fullscreen |
|
1576 case 77: el.mute(); break; // mute |
|
1577 case 81: el.unload(); break; // unload/stop |
|
1578 } |
|
1579 |
|
1580 } |
|
1581 |
|
1582 }); |
|
1583 |
|
1584 flowplayer(function(api, root) { |
|
1585 |
|
1586 // no keyboard configured |
|
1587 if (!api.conf.keyboard) return; |
|
1588 |
|
1589 // hover |
|
1590 bean.on(root, "mouseenter mouseleave", function(e) { |
|
1591 focused = !api.disabled && e.type == 'mouseover' ? api : 0; |
|
1592 if (focused) focusedRoot = root; |
|
1593 }); |
|
1594 |
|
1595 var speedhelp = flowplayer.support.video && api.conf.engine !== "flash" && |
|
1596 !!document.createElement('video').playbackRate ? |
|
1597 '<p><em>shift</em> + <em>←</em><em>→</em>slower / faster</p>' : ''; |
|
1598 |
|
1599 // TODO: add to player-layout.html |
|
1600 root.appendChild(common.createElement('div', { className: 'fp-help' }, '\ |
|
1601 <a class="fp-close"></a>\ |
|
1602 <div class="fp-help-section fp-help-basics">\ |
|
1603 <p><em>space</em>play / pause</p>\ |
|
1604 <p><em>q</em>unload | stop</p>\ |
|
1605 <p><em>f</em>fullscreen</p>' + speedhelp + '\ |
|
1606 </div>\ |
|
1607 <div class="fp-help-section">\ |
|
1608 <p><em>↑</em><em>↓</em>volume</p>\ |
|
1609 <p><em>m</em>mute</p>\ |
|
1610 </div>\ |
|
1611 <div class="fp-help-section">\ |
|
1612 <p><em>←</em><em>→</em>seek</p>\ |
|
1613 <p><em> . </em>seek to previous\ |
|
1614 </p><p><em>1</em><em>2</em>… <em>6</em> seek to 10%, 20% … 60% </p>\ |
|
1615 </div>\ |
|
1616 ')); |
|
1617 |
|
1618 if (api.conf.tooltip) { |
|
1619 var ui = common.find('.fp-ui', root)[0]; |
|
1620 ui.setAttribute('title', 'Hit ? for help'); |
|
1621 bean.one(root, "mouseout.tip", '.fp-ui', function() { |
|
1622 ui.removeAttribute('title'); |
|
1623 }); |
|
1624 } |
|
1625 |
|
1626 bean.on(root, 'click', '.fp-close', function() { |
|
1627 ClassList(root).toggle(IS_HELP); |
|
1628 }); |
|
1629 |
|
1630 api.bind('shutdown', function() { |
|
1631 if (focusedRoot == root) focusedRoot = null; |
|
1632 }); |
|
1633 |
|
1634 }); |
|
1635 |
|
1636 |
|
1637 },{"../common":1,"../flowplayer":18,"bean":20,"class-list":22}],11:[function(_dereq_,module,exports){ |
|
1638 'use strict'; |
|
1639 var flowplayer = _dereq_('../flowplayer'), |
|
1640 isIeMobile = /IEMobile/.test(window.navigator.userAgent), |
|
1641 ClassList = _dereq_('class-list'), |
|
1642 common = _dereq_('../common'), |
|
1643 bean = _dereq_('bean'), |
|
1644 format = _dereq_('./ui').format, |
|
1645 UA = window.navigator.userAgent; |
|
1646 if (flowplayer.support.touch || isIeMobile) { |
|
1647 |
|
1648 flowplayer(function(player, root) { |
|
1649 var isAndroid = /Android/.test(UA) && !/Firefox/.test(UA) && !/Opera/.test(UA), |
|
1650 isSilk = /Silk/.test(UA), |
|
1651 androidVer = isAndroid ? parseFloat(/Android\ (\d\.\d)/.exec(UA)[1], 10) : 0, |
|
1652 rootClasses = ClassList(root); |
|
1653 |
|
1654 // custom load for android |
|
1655 if (isAndroid && !isIeMobile) { |
|
1656 if (!/Chrome/.test(UA) && androidVer < 4) { |
|
1657 var originalLoad = player.load; |
|
1658 player.load = function(video, callback) { |
|
1659 var ret = originalLoad.apply(player, arguments); |
|
1660 player.trigger('ready', [player, player.video]); |
|
1661 return ret; |
|
1662 }; |
|
1663 } |
|
1664 var timer, currentTime = 0; |
|
1665 var resumeTimer = function(api) { |
|
1666 timer = setInterval(function() { |
|
1667 api.video.time = ++currentTime; |
|
1668 api.trigger('progress', [api, currentTime]); |
|
1669 }, 1000); |
|
1670 }; |
|
1671 player.bind('ready pause unload', function() { |
|
1672 if (timer) { |
|
1673 clearInterval(timer); |
|
1674 timer = null; |
|
1675 } |
|
1676 }); |
|
1677 player.bind('ready', function() { |
|
1678 currentTime = 0; |
|
1679 }); |
|
1680 player.bind('resume', function(ev, api) { |
|
1681 if (!api.live) return; |
|
1682 if (currentTime) { return resumeTimer(api); } |
|
1683 player.one('progress', function(ev, api, t) { |
|
1684 if (t === 0) { // https://github.com/flowplayer/flowplayer/issues/727 |
|
1685 resumeTimer(api); |
|
1686 } |
|
1687 }); |
|
1688 }); |
|
1689 } |
|
1690 |
|
1691 // hide volume |
|
1692 if (!flowplayer.support.volume) { |
|
1693 rootClasses.add("no-volume"); |
|
1694 rootClasses.add("no-mute"); |
|
1695 } |
|
1696 rootClasses.add("is-touch"); |
|
1697 if (player.sliders && player.sliders.timeline) player.sliders.timeline.disableAnimation(); |
|
1698 |
|
1699 if (!flowplayer.support.inlineVideo || player.conf.native_fullscreen) player.conf.nativesubtitles = true; |
|
1700 |
|
1701 // fake mouseover effect with click |
|
1702 var hasMoved = false; |
|
1703 bean.on(root, 'touchmove', function() { |
|
1704 hasMoved = true; |
|
1705 }); |
|
1706 bean.on(root, 'touchend click', function(e) { |
|
1707 if (hasMoved) { //not intentional, most likely scrolling |
|
1708 hasMoved = false; |
|
1709 return; |
|
1710 } |
|
1711 |
|
1712 if (player.playing && !rootClasses.contains("is-mouseover")) { |
|
1713 rootClasses.add("is-mouseover"); |
|
1714 rootClasses.remove("is-mouseout"); |
|
1715 e.preventDefault(); |
|
1716 e.stopPropagation(); |
|
1717 return; |
|
1718 } |
|
1719 |
|
1720 if (!player.playing && !player.splash && rootClasses.contains('is-mouseout') && !rootClasses.contains('is-mouseover')) { |
|
1721 setTimeout(function() { |
|
1722 if (!player.playing && !player.splash) { |
|
1723 player.resume(); |
|
1724 } |
|
1725 }, 400); |
|
1726 } |
|
1727 |
|
1728 |
|
1729 }); |
|
1730 |
|
1731 // native fullscreen |
|
1732 if (player.conf.native_fullscreen && typeof document.createElement('video').webkitEnterFullScreen === 'function') { |
|
1733 player.fullscreen = function() { |
|
1734 var video = common.find('video.fp-engine', root)[0]; |
|
1735 video.webkitEnterFullScreen(); |
|
1736 bean.one(video, 'webkitendfullscreen', function() { |
|
1737 common.prop(video, 'controls', true); |
|
1738 common.prop(video, 'controls', false); |
|
1739 }); |
|
1740 }; |
|
1741 } |
|
1742 |
|
1743 |
|
1744 // Android browser gives video.duration == 1 until second 'timeupdate' event |
|
1745 if (isAndroid || isSilk) player.bind("ready", function() { |
|
1746 |
|
1747 var video = common.find('video.fp-engine', root)[0]; |
|
1748 bean.one(video, 'canplay', function() { |
|
1749 video.play(); |
|
1750 }); |
|
1751 video.play(); |
|
1752 |
|
1753 player.bind("progress.dur", function() { |
|
1754 |
|
1755 var duration = video.duration; |
|
1756 |
|
1757 if (duration !== 1) { |
|
1758 player.video.duration = duration; |
|
1759 common.find(".fp-duration", root)[0].innerHTML = format(duration); |
|
1760 player.unbind("progress.dur"); |
|
1761 } |
|
1762 }); |
|
1763 }); |
|
1764 |
|
1765 |
|
1766 }); |
|
1767 |
|
1768 } |
|
1769 |
|
1770 |
|
1771 },{"../common":1,"../flowplayer":18,"./ui":17,"bean":20,"class-list":22}],12:[function(_dereq_,module,exports){ |
|
1772 'use strict'; |
|
1773 var flowplayer = _dereq_('../flowplayer'), |
|
1774 extend = _dereq_('extend-object'), |
|
1775 bean = _dereq_('bean'), |
|
1776 ClassList = _dereq_('class-list'), |
|
1777 common = _dereq_('../common'), |
|
1778 Resolve = _dereq_('./resolve'), |
|
1779 resolver = new Resolve(), |
|
1780 $ = window.jQuery, |
|
1781 externalRe = /^#/; |
|
1782 flowplayer(function(player, root) { |
|
1783 |
|
1784 var conf = extend({ active: 'is-active', advance: true, query: ".fp-playlist a" }, player.conf), |
|
1785 klass = conf.active, rootClasses = ClassList(root); |
|
1786 |
|
1787 // getters |
|
1788 function els() { |
|
1789 return common.find(conf.query, queryRoot()); |
|
1790 } |
|
1791 |
|
1792 function queryRoot() { |
|
1793 if (externalRe.test(conf.query)) return; |
|
1794 return root; |
|
1795 } |
|
1796 |
|
1797 function active() { |
|
1798 return common.find(conf.query + "." + klass, queryRoot()); |
|
1799 } |
|
1800 |
|
1801 |
|
1802 player.play = function(i) { |
|
1803 if (i === undefined) return player.resume(); |
|
1804 if (typeof i === 'number' && !player.conf.playlist[i]) return player; |
|
1805 else if (typeof i != 'number') return player.load.apply(null, arguments); |
|
1806 var arg = extend({index: i}, player.conf.playlist[i]); |
|
1807 if (i === player.video.index) return player.load(arg, function() { player.resume(); }); |
|
1808 player.off('resume.fromfirst'); // Don't start from beginning if clip explicitely chosen |
|
1809 player.load(arg, function() { |
|
1810 player.video.index = i; |
|
1811 }); |
|
1812 return player; |
|
1813 }; |
|
1814 |
|
1815 player.next = function(e) { |
|
1816 if (e) e.preventDefault(); |
|
1817 var current = player.video.index; |
|
1818 if (current != -1) { |
|
1819 current = current === player.conf.playlist.length - 1 ? 0 : current + 1; |
|
1820 player.play(current); |
|
1821 } |
|
1822 return player; |
|
1823 }; |
|
1824 |
|
1825 player.prev = function(e) { |
|
1826 if (e) e.preventDefault(); |
|
1827 var current = player.video.index; |
|
1828 if (current != -1) { |
|
1829 current = current === 0 ? player.conf.playlist.length - 1 : current - 1; |
|
1830 player.play(current); |
|
1831 } |
|
1832 return player; |
|
1833 }; |
|
1834 |
|
1835 player.setPlaylist = function(items) { |
|
1836 player.conf.playlist = items; |
|
1837 delete player.video.index; |
|
1838 generatePlaylist(); |
|
1839 return player; |
|
1840 }; |
|
1841 |
|
1842 player.addPlaylistItem = function(item) { |
|
1843 return player.setPlaylist(player.conf.playlist.concat([item])); |
|
1844 }; |
|
1845 |
|
1846 player.removePlaylistItem = function(idx) { |
|
1847 var pl = player.conf.playlist; |
|
1848 return player.setPlaylist(pl.slice(0, idx).concat(pl.slice(idx+1))); |
|
1849 }; |
|
1850 |
|
1851 bean.on(root, 'click', '.fp-next', player.next); |
|
1852 bean.on(root, 'click', '.fp-prev', player.prev); |
|
1853 |
|
1854 if (conf.advance) { |
|
1855 player.off("finish.pl").on("finish.pl", function(e, player) { |
|
1856 // clip looping |
|
1857 if (player.video.loop) return player.seek(0, function() { player.resume(); }); |
|
1858 // next clip is found or loop |
|
1859 var next = player.video.index >= 0 ? player.video.index + 1 : undefined; |
|
1860 if (next < player.conf.playlist.length || conf.loop) { |
|
1861 next = next === player.conf.playlist.length ? 0 : next; |
|
1862 rootClasses.remove('is-finished'); |
|
1863 setTimeout(function() { // Let other finish callbacks fire first |
|
1864 player.play(next); |
|
1865 }); |
|
1866 |
|
1867 // stop to last clip, play button starts from 1:st clip |
|
1868 } else { |
|
1869 |
|
1870 // If we have multiple items in playlist, start from first |
|
1871 if (player.conf.playlist.length > 1) player.one("resume.fromfirst", function() { |
|
1872 player.play(0); |
|
1873 return false; |
|
1874 }); |
|
1875 } |
|
1876 }); |
|
1877 } |
|
1878 |
|
1879 function generatePlaylist() { |
|
1880 var plEl = common.find('.fp-playlist', root)[0]; |
|
1881 if (!plEl) { |
|
1882 plEl = common.createElement('div', {className: 'fp-playlist'}); |
|
1883 var cntrls = common.find('.fp-next,.fp-prev', root); |
|
1884 if (!cntrls.length) common.insertAfter(root, common.find('video', root)[0], plEl); |
|
1885 else cntrls[0].parentElement.insertBefore(plEl, cntrls[0]); |
|
1886 } |
|
1887 plEl.innerHTML = ''; |
|
1888 if (player.conf.playlist[0].length) { // FP5 style playlist |
|
1889 player.conf.playlist = player.conf.playlist.map(function(itm) { |
|
1890 if (typeof itm === 'string') { |
|
1891 var type = itm.split(Resolve.TYPE_RE)[1]; |
|
1892 return { |
|
1893 sources: [{ |
|
1894 type: type.toLowerCase() === 'm3u8' ? 'application/x-mpegurl' : 'video/' + type, |
|
1895 src: itm |
|
1896 }] |
|
1897 }; |
|
1898 } |
|
1899 return { |
|
1900 sources: itm.map(function(src) { |
|
1901 var s = {}; |
|
1902 Object.keys(src).forEach(function(k) { |
|
1903 s.type = /mpegurl/i.test(k) ? 'application/x-mpegurl' : 'video/' + k; |
|
1904 s.src = src[k]; |
|
1905 }); |
|
1906 return s; |
|
1907 }) |
|
1908 }; |
|
1909 }); |
|
1910 } |
|
1911 player.conf.playlist.forEach(function(item, i) { |
|
1912 var href = item.sources[0].src; |
|
1913 plEl.appendChild(common.createElement('a', { |
|
1914 href: href, |
|
1915 'data-index': i |
|
1916 })); |
|
1917 }); |
|
1918 } |
|
1919 |
|
1920 var playlistInitialized = false; |
|
1921 if (player.conf.playlist.length) { // playlist configured by javascript, generate playlist |
|
1922 playlistInitialized = true; |
|
1923 generatePlaylist(); |
|
1924 if (!player.conf.clip || !player.conf.clip.sources.length) player.conf.clip = player.conf.playlist[0]; |
|
1925 } |
|
1926 |
|
1927 if (els().length && !playlistInitialized) { //generate playlist from existing elements |
|
1928 player.conf.playlist = []; |
|
1929 els().forEach(function(el) { |
|
1930 var src = el.href; |
|
1931 el.setAttribute('data-index', player.conf.playlist.length); |
|
1932 var itm = resolver.resolve(src, player.conf.clip.sources); |
|
1933 if ($) { |
|
1934 extend(itm, $(el).data()); |
|
1935 } |
|
1936 player.conf.playlist.push(itm); |
|
1937 }); |
|
1938 } |
|
1939 |
|
1940 /* click -> play */ |
|
1941 bean.on(externalRe.test(conf.query) ? document : root, "click", conf.query, function(e) { |
|
1942 e.preventDefault(); |
|
1943 var el = e.currentTarget; |
|
1944 var toPlay = Number(el.getAttribute('data-index')); |
|
1945 if (toPlay != -1) { |
|
1946 player.play(toPlay); |
|
1947 } |
|
1948 }); |
|
1949 |
|
1950 // highlight |
|
1951 player.on("load", function(e, api, video) { |
|
1952 if (!player.conf.playlist.length) return; |
|
1953 var prev = active()[0], |
|
1954 prevIndex = prev && prev.getAttribute('data-index'), |
|
1955 index = video.index = video.index || player.video.index || 0, |
|
1956 el = common.find(conf.query +'[data-index="' + index + '"]', queryRoot())[0], |
|
1957 is_last = index == player.conf.playlist.length - 1; |
|
1958 if (prev) ClassList(prev).remove(klass); |
|
1959 if (el) ClassList(el).add(klass); |
|
1960 // index |
|
1961 rootClasses.remove("video" + prevIndex); |
|
1962 rootClasses.add("video" + index); |
|
1963 common.toggleClass(root, "last-video", is_last); |
|
1964 |
|
1965 // video properties |
|
1966 video.index = api.video.index = index; |
|
1967 video.is_last = api.video.is_last = is_last; |
|
1968 |
|
1969 // without namespace callback called only once. unknown rason. |
|
1970 }).on("unload.pl", function() { |
|
1971 if (!player.conf.playlist.length) return; |
|
1972 active().forEach(function(el) { |
|
1973 ClassList(el).toggle(klass); |
|
1974 }); |
|
1975 player.conf.playlist.forEach(function(itm, i) { |
|
1976 rootClasses.remove('video' + i); |
|
1977 }); |
|
1978 }); |
|
1979 |
|
1980 if (player.conf.playlist.length) { |
|
1981 // disable single clip looping |
|
1982 player.conf.loop = false; |
|
1983 } |
|
1984 |
|
1985 |
|
1986 }); |
|
1987 |
|
1988 },{"../common":1,"../flowplayer":18,"./resolve":13,"bean":20,"class-list":22,"extend-object":26}],13:[function(_dereq_,module,exports){ |
|
1989 'use strict'; |
|
1990 var TYPE_RE = /\.(\w{3,4})(\?.*)?$/i, |
|
1991 extend = _dereq_('extend-object'); |
|
1992 |
|
1993 function parseSource(el) { |
|
1994 |
|
1995 var src = el.attr("src"), |
|
1996 type = el.attr("type") || "", |
|
1997 suffix = src.split(TYPE_RE)[1]; |
|
1998 type = type.toLowerCase(); |
|
1999 return extend(el.data(), { src: src, suffix: suffix || type, type: type || suffix }); |
|
2000 } |
|
2001 |
|
2002 function getType(typ) { |
|
2003 if (/mpegurl/i.test(typ)) return 'application/x-mpegurl'; |
|
2004 return 'video/' + typ; |
|
2005 } |
|
2006 |
|
2007 /* Resolves video object from initial configuration and from load() method */ |
|
2008 module.exports = function URLResolver() { |
|
2009 var self = this; |
|
2010 |
|
2011 self.sourcesFromVideoTag = function(videoTag, $) { |
|
2012 /* global $ */ |
|
2013 var sources = []; |
|
2014 // initial sources |
|
2015 $("source", videoTag).each(function() { |
|
2016 sources.push(parseSource($(this))); |
|
2017 }); |
|
2018 |
|
2019 if (!sources.length && videoTag.length) sources.push(parseSource(videoTag)); |
|
2020 |
|
2021 return sources; |
|
2022 }; |
|
2023 |
|
2024 |
|
2025 self.resolve = function(video, sources) { |
|
2026 if (!video) return { sources: sources }; |
|
2027 |
|
2028 if (typeof video == 'string') { |
|
2029 video = { src: video, sources: [] }; |
|
2030 video.sources = (sources || []).map(function(source) { |
|
2031 var suffix = source.src.split(TYPE_RE)[1]; |
|
2032 return {type: source.type, src: video.src.replace(TYPE_RE, '.' + suffix + "$2")}; |
|
2033 }); |
|
2034 } |
|
2035 |
|
2036 if (video instanceof Array) { |
|
2037 video = { |
|
2038 sources: video.map(function(src) { |
|
2039 if (src.type && src.src) return src; |
|
2040 return Object.keys(src).reduce(function(m, typ) { |
|
2041 return extend(m, { |
|
2042 type: getType(typ), |
|
2043 src: src[typ] |
|
2044 }); |
|
2045 }, {}); |
|
2046 }) |
|
2047 }; |
|
2048 } |
|
2049 |
|
2050 return video; |
|
2051 }; |
|
2052 }; |
|
2053 |
|
2054 module.exports.TYPE_RE = TYPE_RE; |
|
2055 |
|
2056 },{"extend-object":26}],14:[function(_dereq_,module,exports){ |
|
2057 'use strict'; |
|
2058 // skip IE policies |
|
2059 // document.ondragstart = function () { return false; }; |
|
2060 // |
|
2061 var ClassList = _dereq_('class-list'), |
|
2062 bean = _dereq_('bean'), |
|
2063 common = _dereq_('../common'); |
|
2064 |
|
2065 |
|
2066 // execute function every <delay> ms |
|
2067 var throttle = function(fn, delay) { |
|
2068 var locked; |
|
2069 |
|
2070 return function () { |
|
2071 if (!locked) { |
|
2072 fn.apply(this, arguments); |
|
2073 locked = 1; |
|
2074 setTimeout(function () { locked = 0; }, delay); |
|
2075 } |
|
2076 }; |
|
2077 }; |
|
2078 |
|
2079 |
|
2080 var slider = function(root, rtl) { |
|
2081 var IS_IPAD = /iPad/.test(navigator.userAgent) && !/CriOS/.test(navigator.userAgent); |
|
2082 |
|
2083 var progress = common.lastChild(root), |
|
2084 rootClasses = ClassList(root), |
|
2085 progressClasses = ClassList(progress), |
|
2086 disabled, |
|
2087 offset, |
|
2088 width, |
|
2089 height, |
|
2090 vertical, |
|
2091 size, |
|
2092 maxValue, |
|
2093 max, |
|
2094 skipAnimation = false, |
|
2095 |
|
2096 /* private */ |
|
2097 calc = function() { |
|
2098 offset = common.offset(root); |
|
2099 width = common.width(root); |
|
2100 height = common.height(root); |
|
2101 |
|
2102 /* exit from fullscreen can mess this up.*/ |
|
2103 // vertical = height > width; |
|
2104 |
|
2105 size = vertical ? height : width; |
|
2106 max = toDelta(maxValue); |
|
2107 }, |
|
2108 |
|
2109 fire = function(value) { |
|
2110 if (!disabled && value != api.value && (!maxValue || value < maxValue)) { |
|
2111 bean.fire(root, 'slide', [ value ]); |
|
2112 api.value = value; |
|
2113 } |
|
2114 }, |
|
2115 |
|
2116 mousemove = function(e) { |
|
2117 var pageX = e.pageX || e.clientX; |
|
2118 if (!pageX && e.originalEvent && e.originalEvent.touches && e.originalEvent.touches.length) { |
|
2119 pageX = e.originalEvent.touches[0].pageX; |
|
2120 } |
|
2121 var delta = vertical ? e.pageY - offset.top : pageX - offset.left; |
|
2122 delta = Math.max(0, Math.min(max || size, delta)); |
|
2123 |
|
2124 var value = delta / size; |
|
2125 if (vertical) value = 1 - value; |
|
2126 if (rtl) value = 1 - value; |
|
2127 return move(value, 0, true); |
|
2128 }, |
|
2129 |
|
2130 move = function(value, speed) { |
|
2131 if (speed === undefined) { speed = 0; } |
|
2132 if (value > 1) value = 1; |
|
2133 |
|
2134 var to = (Math.round(value * 1000) / 10) + "%"; |
|
2135 |
|
2136 if (!maxValue || value <= maxValue) { |
|
2137 progressClasses.remove('animated'); |
|
2138 if (skipAnimation) { |
|
2139 progressClasses.remove('animated'); |
|
2140 } else { |
|
2141 progressClasses.add('animated'); |
|
2142 common.css(progress, 'transition-duration', (speed || 0) + 'ms'); |
|
2143 } |
|
2144 common.css(progress, 'width', to); |
|
2145 } |
|
2146 |
|
2147 return value; |
|
2148 }, |
|
2149 |
|
2150 toDelta = function(value) { |
|
2151 return Math.max(0, Math.min(size, vertical ? (1 - value) * height : value * width)); |
|
2152 }, |
|
2153 |
|
2154 /* public */ |
|
2155 api = { |
|
2156 |
|
2157 max: function(value) { |
|
2158 maxValue = value; |
|
2159 }, |
|
2160 |
|
2161 disable: function(flag) { |
|
2162 disabled = flag; |
|
2163 }, |
|
2164 |
|
2165 slide: function(value, speed, fireEvent) { |
|
2166 calc(); |
|
2167 if (fireEvent) fire(value); |
|
2168 move(value, speed); |
|
2169 }, |
|
2170 |
|
2171 // Should animation be handled via css |
|
2172 disableAnimation: function(value, alsoCssAnimations) { |
|
2173 skipAnimation = value !== false; |
|
2174 common.toggleClass(root, 'no-animation', !!alsoCssAnimations); |
|
2175 } |
|
2176 |
|
2177 }; |
|
2178 |
|
2179 calc(); |
|
2180 |
|
2181 // bound dragging into document |
|
2182 bean.on(root, 'mousedown.sld touchstart', function(e) { |
|
2183 e.preventDefault(); |
|
2184 |
|
2185 if (!disabled) { |
|
2186 // begin --> recalculate. allows dynamic resizing of the slider |
|
2187 var delayedFire = throttle(fire, 100); |
|
2188 calc(); |
|
2189 api.dragging = true; |
|
2190 rootClasses.add('is-dragging'); |
|
2191 fire(mousemove(e)); |
|
2192 |
|
2193 bean.on(document, 'mousemove.sld touchmove.sld', function(e) { |
|
2194 e.preventDefault(); |
|
2195 delayedFire(mousemove(e)); |
|
2196 |
|
2197 }); |
|
2198 bean.one(document, 'mouseup touchend', function() { |
|
2199 api.dragging = false; |
|
2200 rootClasses.remove('is-dragging'); |
|
2201 bean.off(document, 'mousemove.sld touchmove.sld'); |
|
2202 }); |
|
2203 |
|
2204 } |
|
2205 |
|
2206 }); |
|
2207 return api; |
|
2208 }; |
|
2209 |
|
2210 module.exports = slider; |
|
2211 |
|
2212 },{"../common":1,"bean":20,"class-list":22}],15:[function(_dereq_,module,exports){ |
|
2213 'use strict'; |
|
2214 var flowplayer = _dereq_('../flowplayer'), |
|
2215 common = _dereq_('../common'), |
|
2216 bean = _dereq_('bean'), |
|
2217 ClassList = _dereq_('class-list'); |
|
2218 |
|
2219 flowplayer.defaults.subtitleParser = function(txt) { |
|
2220 var TIMECODE_RE = /^(([0-9]{2}:){1,2}[0-9]{2}[,.][0-9]{3}) --\> (([0-9]{2}:){1,2}[0-9]{2}[,.][0-9]{3})(.*)/; |
|
2221 |
|
2222 function seconds(timecode) { |
|
2223 var els = timecode.split(':'); |
|
2224 if (els.length == 2) els.unshift(0); |
|
2225 return els[0] * 60 * 60 + els[1] * 60 + parseFloat(els[2].replace(',','.')); |
|
2226 } |
|
2227 |
|
2228 var entries = []; |
|
2229 for (var i = 0, lines = txt.split("\n"), len = lines.length, entry = {}, title, timecode, text, cue; i < len; i++) { |
|
2230 timecode = TIMECODE_RE.exec(lines[i]); |
|
2231 |
|
2232 if (timecode) { |
|
2233 |
|
2234 // title |
|
2235 title = lines[i - 1]; |
|
2236 |
|
2237 // text |
|
2238 text = "<p>" + lines[++i] + "</p><br/>"; |
|
2239 while (typeof lines[++i] === 'string' && lines[i].trim() && i < lines.length) text += "<p>" + lines[i] + "</p><br/>"; |
|
2240 |
|
2241 // entry |
|
2242 entry = { |
|
2243 title: title, |
|
2244 startTime: seconds(timecode[1]), |
|
2245 endTime: seconds(timecode[3]), |
|
2246 text: text |
|
2247 }; |
|
2248 entries.push(entry); |
|
2249 } |
|
2250 } |
|
2251 return entries; |
|
2252 }; |
|
2253 |
|
2254 flowplayer(function(p, root) { |
|
2255 var wrapClasses, currentPoint, wrap, |
|
2256 rootClasses = ClassList(root), |
|
2257 subtitleControl; |
|
2258 |
|
2259 var createSubtitleControl = function() { |
|
2260 subtitleControl = common.createElement('a', {className: 'fp-menu'}); |
|
2261 var menu = common.createElement('ul', {className: 'fp-dropdown fp-dropup'}); |
|
2262 menu.appendChild(common.createElement('li', {'data-subtitle-index': -1}, 'No subtitles')); |
|
2263 (p.video.subtitles || []).forEach(function(st, i) { |
|
2264 var srcLang = st.srclang || 'en', |
|
2265 label = st.label || 'Default (' + srcLang + ')'; |
|
2266 var item = common.createElement('li', {'data-subtitle-index': i}, label); |
|
2267 menu.appendChild(item); |
|
2268 }); |
|
2269 subtitleControl.appendChild(menu); |
|
2270 common.find('.fp-controls', root)[0].appendChild(subtitleControl); |
|
2271 return subtitleControl; |
|
2272 }; |
|
2273 |
|
2274 bean.on(root, 'click', '.fp-menu', function(ev) { |
|
2275 ClassList(subtitleControl).toggle('dropdown-open'); |
|
2276 }); |
|
2277 |
|
2278 bean.on(root, 'click', '.fp-menu li[data-subtitle-index]', function(ev) { |
|
2279 var idx = ev.target.getAttribute('data-subtitle-index'); |
|
2280 if (idx === '-1') return p.disableSubtitles(); |
|
2281 p.loadSubtitles(idx); |
|
2282 }); |
|
2283 |
|
2284 var createUIElements = function() { |
|
2285 var playerEl = common.find('.fp-player', root)[0]; |
|
2286 wrap = common.find('.fp-subtitle', root)[0]; |
|
2287 wrap = wrap || common.appendTo(common.createElement('div', {'class': 'fp-subtitle'}), playerEl); |
|
2288 Array.prototype.forEach.call(wrap.children, common.removeNode); |
|
2289 wrapClasses = ClassList(wrap); |
|
2290 common.find('.fp-menu', root).forEach(common.removeNode); |
|
2291 createSubtitleControl(); |
|
2292 }; |
|
2293 |
|
2294 |
|
2295 p.on('ready', function(ev, player, video) { |
|
2296 var conf = player.conf; |
|
2297 if (flowplayer.support.subtitles && conf.nativesubtitles && player.engine.engineName == 'html5') { |
|
2298 var setMode = function(mode) { |
|
2299 var tracks = common.find('video', root)[0].textTracks; |
|
2300 if (!tracks.length) return; |
|
2301 tracks[0].mode = mode; |
|
2302 }; |
|
2303 if (!video.subtitles || !video.subtitles.length) return; |
|
2304 var videoTag = common.find('video.fp-engine', root)[0]; |
|
2305 video.subtitles.forEach(function(st) { |
|
2306 videoTag.appendChild(common.createElement('track', { |
|
2307 kind: 'subtitles', |
|
2308 srclang: st.srclang || 'en', |
|
2309 label: st.label || 'en', |
|
2310 src: st.src, |
|
2311 'default': st['default'] |
|
2312 })); |
|
2313 }); |
|
2314 setMode('disabled'); |
|
2315 setMode('showing'); |
|
2316 return; |
|
2317 } |
|
2318 |
|
2319 player.subtitles = []; |
|
2320 |
|
2321 createUIElements(); |
|
2322 |
|
2323 rootClasses.remove('has-menu'); |
|
2324 |
|
2325 p.disableSubtitles(); |
|
2326 |
|
2327 if (!video.subtitles || !video.subtitles.length) return; |
|
2328 |
|
2329 rootClasses.add('has-menu'); |
|
2330 var defaultSubtitle = video.subtitles.filter(function(one) { |
|
2331 return one['default']; |
|
2332 })[0]; |
|
2333 if (defaultSubtitle) player.loadSubtitles(video.subtitles.indexOf(defaultSubtitle)); |
|
2334 }); |
|
2335 |
|
2336 p.bind("cuepoint", function(e, api, cue) { |
|
2337 if (cue.subtitle) { |
|
2338 currentPoint = cue.index; |
|
2339 common.html(wrap, cue.subtitle.text); |
|
2340 wrapClasses.add('fp-active'); |
|
2341 } else if (cue.subtitleEnd) { |
|
2342 wrapClasses.remove('fp-active'); |
|
2343 currentPoint = cue.index; |
|
2344 } |
|
2345 }); |
|
2346 |
|
2347 p.bind("seek", function(e, api, time) { |
|
2348 // Clear future subtitles if seeking backwards |
|
2349 if (currentPoint && p.cuepoints[currentPoint] && p.cuepoints[currentPoint].time > time) { |
|
2350 wrapClasses.remove('fp-active'); |
|
2351 currentPoint = null; |
|
2352 } |
|
2353 (p.cuepoints || []).forEach(function(cue) { |
|
2354 var entry = cue.subtitle; |
|
2355 //Trigger cuepoint if start time before seek position and end time nonexistent or in the future |
|
2356 if (entry && currentPoint != cue.index) { |
|
2357 if (time >= cue.time && (!entry.endTime || time <= entry.endTime)) p.trigger("cuepoint", [p, cue]); |
|
2358 } // Also handle cuepoints that act as the removal trigger |
|
2359 else if (cue.subtitleEnd && time >= cue.time && cue.index == currentPoint + 1) p.trigger("cuepoint", [p, cue]); |
|
2360 }); |
|
2361 |
|
2362 }); |
|
2363 |
|
2364 var setActiveSubtitleClass = function(idx) { |
|
2365 common.toggleClass(common.find('li.active', root)[0], 'active'); |
|
2366 common.toggleClass(common.find('li[data-subtitle-index="' + idx + '"]', root)[0], 'active'); |
|
2367 }; |
|
2368 |
|
2369 p.disableSubtitles = function() { |
|
2370 p.subtitles = []; |
|
2371 (p.cuepoints || []).forEach(function(c) { |
|
2372 if (c.subtitle || c.subtitleEnd) p.removeCuepoint(c); |
|
2373 }); |
|
2374 if (wrap) Array.prototype.forEach.call(wrap.children, common.removeNode); |
|
2375 setActiveSubtitleClass(-1); |
|
2376 return p; |
|
2377 }; |
|
2378 |
|
2379 p.loadSubtitles = function(i) { |
|
2380 //First remove possible old subtitles |
|
2381 p.disableSubtitles(); |
|
2382 |
|
2383 var st = p.video.subtitles[i]; |
|
2384 |
|
2385 var url = st.src; |
|
2386 if (!url) return; |
|
2387 setActiveSubtitleClass(i); |
|
2388 common.xhrGet(url, function(txt) { |
|
2389 var entries = p.conf.subtitleParser(txt); |
|
2390 entries.forEach(function(entry) { |
|
2391 var cue = { time: entry.startTime, subtitle: entry, visible: false }; |
|
2392 p.subtitles.push(entry); |
|
2393 p.addCuepoint(cue); |
|
2394 p.addCuepoint({ time: entry.endTime, subtitleEnd: entry.title, visible: false }); |
|
2395 |
|
2396 // initial cuepoint |
|
2397 if (entry.startTime === 0 && !p.video.time) { |
|
2398 p.trigger("cuepoint", [p, cue]); |
|
2399 } |
|
2400 }); |
|
2401 }, function() { |
|
2402 p.trigger("error", {code: 8, url: url }); |
|
2403 return false; |
|
2404 }); |
|
2405 return p; |
|
2406 }; |
|
2407 }); |
|
2408 |
|
2409 |
|
2410 },{"../common":1,"../flowplayer":18,"bean":20,"class-list":22}],16:[function(_dereq_,module,exports){ |
|
2411 'use strict'; |
|
2412 /* global ActiveXObject */ |
|
2413 var flowplayer = _dereq_('../flowplayer'), |
|
2414 extend = _dereq_('extend-object'); |
|
2415 (function() { |
|
2416 |
|
2417 var parseIpadVersion = function(UA) { |
|
2418 var e = /Version\/(\d\.\d)/.exec(UA); |
|
2419 if (e && e.length > 1) { |
|
2420 return parseFloat(e[1], 10); |
|
2421 } |
|
2422 return 0; |
|
2423 }; |
|
2424 |
|
2425 var createVideoTag = function() { |
|
2426 var videoTag = document.createElement('video'); |
|
2427 videoTag.loop = true; |
|
2428 videoTag.autoplay = true; |
|
2429 videoTag.preload = true; |
|
2430 return videoTag; |
|
2431 }; |
|
2432 |
|
2433 var b = {}, |
|
2434 ua = navigator.userAgent.toLowerCase(), |
|
2435 match = /(chrome)[ \/]([\w.]+)/.exec(ua) || |
|
2436 /(safari)[ \/]([\w.]+)/.exec(ua) || |
|
2437 /(webkit)[ \/]([\w.]+)/.exec(ua) || |
|
2438 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || |
|
2439 /(msie) ([\w.]+)/.exec(ua) || |
|
2440 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; |
|
2441 |
|
2442 if (match[1]) { |
|
2443 b[match[1]] = true; |
|
2444 b.version = match[2] || "0"; |
|
2445 } |
|
2446 |
|
2447 var video = createVideoTag(), |
|
2448 UA = navigator.userAgent, |
|
2449 IS_IE = b.msie || /Trident\/7/.test(UA), |
|
2450 IS_IPAD = /iPad|MeeGo/.test(UA) && !/CriOS/.test(UA), |
|
2451 IS_IPAD_CHROME = /iPad/.test(UA) && /CriOS/.test(UA), |
|
2452 IS_IPHONE = /iP(hone|od)/i.test(UA) && !/iPad/.test(UA) && !/IEMobile/i.test(UA), |
|
2453 IS_ANDROID = /Android/.test(UA) && !/Firefox/.test(UA), |
|
2454 IS_ANDROID_FIREFOX = /Android/.test(UA) && /Firefox/.test(UA), |
|
2455 IS_SILK = /Silk/.test(UA), |
|
2456 IS_WP = /IEMobile/.test(UA), |
|
2457 WP_VER = IS_WP ? parseFloat(/Windows\ Phone\ (\d+\.\d+)/.exec(UA)[1], 10) : 0, |
|
2458 IE_MOBILE_VER = IS_WP ? parseFloat(/IEMobile\/(\d+\.\d+)/.exec(UA)[1], 10) : 0, |
|
2459 IPAD_VER = IS_IPAD ? parseIpadVersion(UA) : 0, |
|
2460 ANDROID_VER = IS_ANDROID ? parseFloat(/Android\ (\d\.\d)/.exec(UA)[1], 10) : 0, |
|
2461 s = extend(flowplayer.support, { |
|
2462 |
|
2463 browser: b, |
|
2464 subtitles: !!video.addTextTrack, |
|
2465 fullscreen: typeof document.webkitCancelFullScreen == 'function' && !/Mac OS X 10_5.+Version\/5\.0\.\d Safari/.test(UA) || |
|
2466 document.mozFullScreenEnabled || |
|
2467 typeof document.exitFullscreen == 'function' || |
|
2468 typeof document.msExitFullscreen == 'function', |
|
2469 inlineBlock: !(IS_IE && b.version < 8), |
|
2470 touch: ('ontouchstart' in window), |
|
2471 dataload: !IS_IPAD && !IS_IPHONE && !IS_WP, |
|
2472 zeropreload: !IS_IE && !IS_ANDROID, // IE supports only preload=metadata |
|
2473 volume: !IS_IPAD && !IS_ANDROID && !IS_IPHONE && !IS_SILK && !IS_IPAD_CHROME, |
|
2474 cachedVideoTag: !IS_IPAD && !IS_IPHONE && !IS_IPAD_CHROME && !IS_WP, |
|
2475 firstframe: !IS_IPHONE && !IS_IPAD && !IS_ANDROID && !IS_SILK && !IS_IPAD_CHROME && !IS_WP && !IS_ANDROID_FIREFOX, |
|
2476 inlineVideo: !IS_IPHONE && (!IS_WP || (WP_VER >= 8.1 && IE_MOBILE_VER >= 11)) && (!IS_ANDROID || ANDROID_VER >= 3), |
|
2477 hlsDuration: !IS_ANDROID && (!b.safari || IS_IPAD || IS_IPHONE || IS_IPAD_CHROME), |
|
2478 seekable: !IS_IPAD && !IS_IPAD_CHROME |
|
2479 }); |
|
2480 |
|
2481 // flashVideo |
|
2482 try { |
|
2483 var plugin = navigator.plugins["Shockwave Flash"], |
|
2484 ver = IS_IE ? new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable('$version') : plugin.description; |
|
2485 if (!IS_IE && !plugin[0].enabledPlugin) s.flashVideo = false; |
|
2486 else { |
|
2487 |
|
2488 ver = ver.split(/\D+/); |
|
2489 if (ver.length && !ver[0]) ver = ver.slice(1); |
|
2490 |
|
2491 s.flashVideo = ver[0] > 9 || ver[0] == 9 && ver[3] >= 115; |
|
2492 } |
|
2493 |
|
2494 } catch (ignored) {} |
|
2495 try { |
|
2496 s.video = !!video.canPlayType; |
|
2497 if (s.video) video.canPlayType('video/mp4'); |
|
2498 } catch (e) { |
|
2499 s.video = false; |
|
2500 } |
|
2501 |
|
2502 // animation |
|
2503 s.animation = (function() { |
|
2504 var vendors = ['','Webkit','Moz','O','ms','Khtml'], el = document.createElement('p'); |
|
2505 |
|
2506 for (var i = 0; i < vendors.length; i++) { |
|
2507 if (typeof el.style[vendors[i] + 'AnimationName'] !== 'undefined') return true; |
|
2508 } |
|
2509 })(); |
|
2510 |
|
2511 |
|
2512 |
|
2513 })(); |
|
2514 |
|
2515 |
|
2516 },{"../flowplayer":18,"extend-object":26}],17:[function(_dereq_,module,exports){ |
|
2517 'use strict'; |
|
2518 var flowplayer = _dereq_('../flowplayer'), |
|
2519 common = _dereq_('../common'), |
|
2520 ClassList = _dereq_('class-list'), |
|
2521 bean = _dereq_('bean'), |
|
2522 slider = _dereq_('./slider'); |
|
2523 |
|
2524 function zeropad(val) { |
|
2525 val = parseInt(val, 10); |
|
2526 return val >= 10 ? val : "0" + val; |
|
2527 } |
|
2528 |
|
2529 // display seconds in hh:mm:ss format |
|
2530 function format(sec) { |
|
2531 |
|
2532 sec = sec || 0; |
|
2533 |
|
2534 var h = Math.floor(sec / 3600), |
|
2535 min = Math.floor(sec / 60); |
|
2536 |
|
2537 sec = sec - (min * 60); |
|
2538 |
|
2539 if (h >= 1) { |
|
2540 min -= h * 60; |
|
2541 return h + ":" + zeropad(min) + ":" + zeropad(sec); |
|
2542 } |
|
2543 |
|
2544 return zeropad(min) + ":" + zeropad(sec); |
|
2545 } |
|
2546 |
|
2547 flowplayer(function(api, root) { |
|
2548 |
|
2549 var conf = api.conf, |
|
2550 support = flowplayer.support, |
|
2551 hovertimer, |
|
2552 rootClasses = ClassList(root); |
|
2553 common.find('.fp-ratio,.fp-ui', root).forEach(common.removeNode); |
|
2554 rootClasses.add('flowplayer'); |
|
2555 root.appendChild(common.createElement('div', {className: 'fp-ratio'})); |
|
2556 var ui = common.createElement('div', {className: 'fp-ui'}, '\ |
|
2557 <div class="waiting"><em></em><em></em><em></em></div>\ |
|
2558 <a class="fullscreen"></a>\ |
|
2559 <a class="unload"></a>\ |
|
2560 <p class="speed"></p>\ |
|
2561 <div class="controls">\ |
|
2562 <a class="play"></a>\ |
|
2563 <div class="timeline">\ |
|
2564 <div class="buffer"></div>\ |
|
2565 <div class="progress"></div>\ |
|
2566 </div>\ |
|
2567 <div class="timeline-tooltip fp-tooltip"></div>\ |
|
2568 <div class="volume">\ |
|
2569 <a class="mute"></a>\ |
|
2570 <div class="volumeslider">\ |
|
2571 <div class="volumelevel"></div>\ |
|
2572 </div>\ |
|
2573 </div>\ |
|
2574 </div>\ |
|
2575 <div class="time">\ |
|
2576 <em class="elapsed">00:00</em>\ |
|
2577 <em class="remaining"></em>\ |
|
2578 <em class="duration">00:00</em>\ |
|
2579 </div>\ |
|
2580 <div class="message"><h2></h2><p></p></div>'.replace(/class="/g, 'class="fp-')); |
|
2581 root.appendChild(ui); |
|
2582 function find(klass) { |
|
2583 return common.find(".fp-" + klass, root)[0]; |
|
2584 } |
|
2585 |
|
2586 // widgets |
|
2587 var progress = find("progress"), |
|
2588 buffer = find("buffer"), |
|
2589 elapsed = find("elapsed"), |
|
2590 remaining = find("remaining"), |
|
2591 waiting = find("waiting"), |
|
2592 ratio = find("ratio"), |
|
2593 speed = find("speed"), |
|
2594 speedClasses = ClassList(speed), |
|
2595 durationEl = find("duration"), |
|
2596 controls = find('controls'), |
|
2597 timelineTooltip = find('timeline-tooltip'), |
|
2598 origRatio = common.css(ratio, 'padding-top'), |
|
2599 |
|
2600 // sliders |
|
2601 timeline = find("timeline"), |
|
2602 timelineApi = slider(timeline, api.rtl), |
|
2603 |
|
2604 volume = find("volume"), |
|
2605 fullscreen = find("fullscreen"), |
|
2606 volumeSlider = find("volumeslider"), |
|
2607 volumeApi = slider(volumeSlider, api.rtl), |
|
2608 noToggle = rootClasses.contains('fixed-controls') || rootClasses.contains('no-toggle'); |
|
2609 |
|
2610 timelineApi.disableAnimation(rootClasses.contains('is-touch')); |
|
2611 api.sliders = api.sliders || {}; |
|
2612 api.sliders.timeline = timelineApi; |
|
2613 api.sliders.volume = volumeApi; |
|
2614 |
|
2615 // aspect ratio |
|
2616 function setRatio(val) { |
|
2617 common.css(ratio, 'padding-top', val * 100 + "%"); |
|
2618 if (!support.inlineBlock) common.height(common.find('object', root)[0], common.height(root)); |
|
2619 } |
|
2620 |
|
2621 function hover(flag) { |
|
2622 if (flag) { |
|
2623 rootClasses.add('is-mouseover'); |
|
2624 rootClasses.remove('is-mouseout'); |
|
2625 } else { |
|
2626 rootClasses.add('is-mouseout'); |
|
2627 rootClasses.remove('is-mouseover'); |
|
2628 } |
|
2629 } |
|
2630 |
|
2631 // loading... |
|
2632 if (!support.animation) common.html(waiting, "<p>loading …</p>"); |
|
2633 |
|
2634 if (conf.ratio) setRatio(conf.ratio); |
|
2635 |
|
2636 // no fullscreen in IFRAME |
|
2637 try { |
|
2638 if (!conf.fullscreen) common.removeNode(fullscreen); |
|
2639 |
|
2640 } catch (e) { |
|
2641 common.removeNode(fullscreen); |
|
2642 } |
|
2643 |
|
2644 api.on("ready", function(ev, api, video) { |
|
2645 |
|
2646 var duration = api.video.duration; |
|
2647 |
|
2648 timelineApi.disable(api.disabled || !duration); |
|
2649 |
|
2650 if (conf.adaptiveRatio && !isNaN(video.height / video.width)) setRatio(video.height / video.width, true); |
|
2651 |
|
2652 // initial time & volume |
|
2653 common.html([durationEl, remaining], format(duration)); |
|
2654 |
|
2655 // do we need additional space for showing hour |
|
2656 common.toggleClass(root, 'is-long', duration >= 3600); |
|
2657 volumeApi.slide(api.volumeLevel); |
|
2658 |
|
2659 if (api.engine.engineName === 'flash') timelineApi.disableAnimation(true, true); |
|
2660 else timelineApi.disableAnimation(false); |
|
2661 common.find('.fp-title', ui).forEach(common.removeNode); |
|
2662 if (video.title) { |
|
2663 common.prepend(ui, common.createElement('div', { |
|
2664 className: 'fp-title' |
|
2665 }, video.title)); |
|
2666 } |
|
2667 |
|
2668 |
|
2669 }).on("unload", function() { |
|
2670 if (!origRatio) common.css(ratio, "paddingTop", ""); |
|
2671 timelineApi.slide(0); |
|
2672 |
|
2673 // buffer |
|
2674 }).on("buffer", function() { |
|
2675 var video = api.video, |
|
2676 max = video.buffer / video.duration; |
|
2677 |
|
2678 if (!video.seekable && support.seekable) timelineApi.max(max); |
|
2679 if (max < 1) common.css(buffer, "width", (max * 100) + "%"); |
|
2680 else common.css(buffer, 'width', '100%'); |
|
2681 |
|
2682 }).on("speed", function(e, api, val) { |
|
2683 common.text(speed, val + "x"); |
|
2684 speedClasses.add('fp-hilite'); |
|
2685 setTimeout(function() { speedClasses.remove('fp-hilite'); }, 1000); |
|
2686 |
|
2687 }).on("buffered", function() { |
|
2688 common.css(buffer, 'width', '100%'); |
|
2689 timelineApi.max(1); |
|
2690 |
|
2691 // progress |
|
2692 }).on("progress", function() { |
|
2693 |
|
2694 var time = api.video.time, |
|
2695 duration = api.video.duration; |
|
2696 |
|
2697 if (!timelineApi.dragging) { |
|
2698 timelineApi.slide(time / duration, api.seeking ? 0 : 250); |
|
2699 } |
|
2700 |
|
2701 common.html(elapsed, format(time)); |
|
2702 common.html(remaining, '-' + format(duration - time)); |
|
2703 |
|
2704 }).on("finish resume seek", function(e) { |
|
2705 common.toggleClass(root, "is-finished", e.type == "finish"); |
|
2706 |
|
2707 }).on("stop", function() { |
|
2708 common.html(elapsed, format(0)); |
|
2709 timelineApi.slide(0, 100); |
|
2710 |
|
2711 }).on("finish", function() { |
|
2712 common.html(elapsed, format(api.video.duration)); |
|
2713 timelineApi.slide(1, 100); |
|
2714 rootClasses.remove('is-seeking'); |
|
2715 |
|
2716 // misc |
|
2717 }).on("beforeseek", function() { |
|
2718 //TODO FIXME |
|
2719 //progress.stop(); |
|
2720 |
|
2721 }).on("volume", function() { |
|
2722 volumeApi.slide(api.volumeLevel); |
|
2723 |
|
2724 |
|
2725 }).on("disable", function() { |
|
2726 var flag = api.disabled; |
|
2727 timelineApi.disable(flag); |
|
2728 volumeApi.disable(flag); |
|
2729 common.toggleClass(root, 'is-disabled', api.disabled); |
|
2730 |
|
2731 }).on("mute", function(e, api, flag) { |
|
2732 common.toggleClass(root, 'is-muted', flag); |
|
2733 |
|
2734 }).on("error", function(e, api, error) { |
|
2735 common.removeClass(root, 'is-loading'); |
|
2736 common.addClass(root, 'is-error'); |
|
2737 if (error) { |
|
2738 error.message = conf.errors[error.code]; |
|
2739 api.error = true; |
|
2740 |
|
2741 var el = common.find('.fp-message', root)[0], |
|
2742 video = error.video || api.video; |
|
2743 common.find('h2', el)[0].innerHTML = (api.engine && api.engine.engineName || 'html5') + ": " + error.message; |
|
2744 common.find('p', el)[0].innerHTML = error.url || video.url || video.src || conf.errorUrls[error.code]; |
|
2745 api.off("mouseenter click"); |
|
2746 rootClasses.remove('is-mouseover'); |
|
2747 } |
|
2748 |
|
2749 |
|
2750 // hover |
|
2751 }); |
|
2752 //Interaction events |
|
2753 bean.on(root, "mouseenter mouseleave", function(e) { |
|
2754 if (noToggle) return; |
|
2755 |
|
2756 var is_over = e.type == "mouseover", |
|
2757 lastMove; |
|
2758 |
|
2759 // is-mouseover/out |
|
2760 hover(is_over); |
|
2761 |
|
2762 if (is_over) { |
|
2763 |
|
2764 var reg = function() { |
|
2765 hover(true); |
|
2766 lastMove = new Date(); |
|
2767 }; |
|
2768 api.on("pause.x volume.x", reg); |
|
2769 bean.on(root, 'mousemove.x', reg); |
|
2770 |
|
2771 hovertimer = setInterval(function() { |
|
2772 if (new Date() - lastMove > conf.mouseoutTimeout) { |
|
2773 hover(false); |
|
2774 lastMove = new Date(); |
|
2775 } |
|
2776 }, 100); |
|
2777 |
|
2778 } else { |
|
2779 bean.off(root, 'mousemove.x'); |
|
2780 api.off("pause.x volume.x"); |
|
2781 clearInterval(hovertimer); |
|
2782 } |
|
2783 |
|
2784 |
|
2785 // allow dragging over the player edge |
|
2786 }); |
|
2787 bean.on(root, "mouseleave", function() { |
|
2788 |
|
2789 if (timelineApi.dragging || volumeApi.dragging) { |
|
2790 rootClasses.add('is-mouseover'); |
|
2791 rootClasses.remove('is-mouseout'); |
|
2792 } |
|
2793 |
|
2794 // click |
|
2795 }); |
|
2796 bean.on(root, "click.player", function(e) { |
|
2797 if (api.disabled) return; |
|
2798 var kls = ClassList(e.target); |
|
2799 if (kls.contains('fp-ui') || kls.contains('fp-engine') || e.flash) { |
|
2800 if (e.preventDefault) e.preventDefault(); |
|
2801 return api.toggle(); |
|
2802 } |
|
2803 }); |
|
2804 |
|
2805 bean.on(root, 'mousemove', '.fp-timeline', function(ev) { |
|
2806 var x = ev.pageX || ev.clientX, |
|
2807 delta = x - common.offset(timeline).left, |
|
2808 percentage = delta / common.width(timeline), |
|
2809 seconds = percentage * api.video.duration; |
|
2810 if (percentage < 0) return; |
|
2811 common.html(timelineTooltip, format(seconds)); |
|
2812 common.css(timelineTooltip, 'left', (x - common.offset(controls).left - common.width(timelineTooltip) / 2) + 'px'); |
|
2813 }); |
|
2814 |
|
2815 bean.on(root, 'contextmenu', function(ev) { |
|
2816 var o = common.offset(common.find('.fp-player', root)[0]), |
|
2817 w = window, |
|
2818 left = ev.clientX - o.left, |
|
2819 t = ev.clientY - (o.top + w.scrollY); |
|
2820 var menu = common.find('.fp-context-menu', root)[0]; |
|
2821 if (!menu) return; |
|
2822 ev.preventDefault(); |
|
2823 common.css(menu, |
|
2824 {left: left + 'px', |
|
2825 top: t + 'px', |
|
2826 display: 'block' |
|
2827 }); |
|
2828 bean.on(root, 'click', '.fp-context-menu', function(ev) { |
|
2829 ev.stopPropagation(); |
|
2830 }); |
|
2831 bean.on(document, 'click.outsidemenu', function(ev) { |
|
2832 common.css(menu, 'display', 'none'); |
|
2833 bean.off(document, 'click.outsidemenu'); |
|
2834 }); |
|
2835 }); |
|
2836 api.on('flashdisabled', function() { |
|
2837 rootClasses.add('is-flash-disabled'); |
|
2838 api.one('ready', function() { |
|
2839 rootClasses.remove('is-flash-disabled'); |
|
2840 common.find('.fp-flash-disabled', root).forEach(common.removeNode); |
|
2841 }); |
|
2842 root.appendChild(common.createElement('div', {className: "fp-flash-disabled"}, 'Adobe Flash is disabled for this page, click player area to enable')); |
|
2843 }); |
|
2844 |
|
2845 // poster -> background image |
|
2846 if (conf.poster) common.css(root, 'background-image', "url(" + conf.poster + ")"); |
|
2847 |
|
2848 var bc = common.css(root, 'background-color'), |
|
2849 has_bg = common.css(root, 'background-image') != "none" || bc && bc != "rgba(0, 0, 0, 0)" && bc != "transparent"; |
|
2850 |
|
2851 // is-poster class |
|
2852 if (has_bg && !conf.splash && !conf.autoplay) { |
|
2853 |
|
2854 api.on("ready stop", function() { |
|
2855 rootClasses.add("is-poster"); |
|
2856 api.one("progress", function() { |
|
2857 rootClasses.remove("is-poster"); |
|
2858 }); |
|
2859 }); |
|
2860 |
|
2861 } |
|
2862 |
|
2863 if (typeof conf.splash === 'string') { |
|
2864 common.css(root, 'background-image', "url('" + conf.splash + "')"); |
|
2865 } |
|
2866 |
|
2867 // default background color if not present |
|
2868 if (!has_bg && api.forcedSplash) { |
|
2869 common.css(root, "background-color", "#555"); |
|
2870 } |
|
2871 |
|
2872 bean.on(root, 'click', '.fp-toggle, .fp-play', function() { |
|
2873 if (api.disabled) return; |
|
2874 api.toggle(); |
|
2875 }); |
|
2876 |
|
2877 /* controlbar elements */ |
|
2878 bean.on(root, 'click', '.fp-mute', function() { api.mute(); }); |
|
2879 bean.on(root, 'click', '.fp-fullscreen', function() { api.fullscreen(); }); |
|
2880 bean.on(root, 'click', '.fp-unload', function() { api.unload(); }); |
|
2881 |
|
2882 bean.on(timeline, 'slide', function(val) { |
|
2883 api.seeking = true; |
|
2884 api.seek(val * api.video.duration); |
|
2885 }); |
|
2886 |
|
2887 bean.on(volumeSlider, 'slide', function(val) { |
|
2888 api.volume(val); |
|
2889 }); |
|
2890 |
|
2891 // times |
|
2892 |
|
2893 var time = find('time'); |
|
2894 bean.on(root, 'click', '.fp-time', function() { |
|
2895 ClassList(time).toggle('is-inverted'); |
|
2896 }); |
|
2897 |
|
2898 hover(noToggle); |
|
2899 |
|
2900 api.on('shutdown', function() { |
|
2901 bean.off(timeline); |
|
2902 bean.off(volumeSlider); |
|
2903 }); |
|
2904 |
|
2905 }); |
|
2906 |
|
2907 |
|
2908 module.exports.format = format; |
|
2909 |
|
2910 },{"../common":1,"../flowplayer":18,"./slider":14,"bean":20,"class-list":22}],18:[function(_dereq_,module,exports){ |
|
2911 'use strict'; |
|
2912 var extend = _dereq_('extend-object'), |
|
2913 isFunction = _dereq_('is-function'), |
|
2914 ClassList = _dereq_('class-list'), |
|
2915 bean = _dereq_('bean'), |
|
2916 common = _dereq_('./common'), |
|
2917 events = _dereq_('./ext/events'); |
|
2918 |
|
2919 var instances = [], |
|
2920 extensions = [], |
|
2921 UA = window.navigator.userAgent; |
|
2922 |
|
2923 |
|
2924 var oldHandler = window.onbeforeunload; |
|
2925 window.onbeforeunload = function(ev) { |
|
2926 instances.forEach(function(api) { |
|
2927 if (api.conf.splash) { |
|
2928 api.unload(); |
|
2929 } else { |
|
2930 api.bind("error", function () { |
|
2931 common.find('.flowplayer.is-error .fp-message').forEach(common.removeNode); |
|
2932 }); |
|
2933 } |
|
2934 }); |
|
2935 if (oldHandler) return oldHandler(ev); |
|
2936 }; |
|
2937 |
|
2938 var supportLocalStorage = false; |
|
2939 try { |
|
2940 if (typeof window.localStorage == "object") { |
|
2941 window.localStorage.flowplayerTestStorage = "test"; |
|
2942 supportLocalStorage = true; |
|
2943 } |
|
2944 } catch (ignored) {} |
|
2945 |
|
2946 var isSafari = /Safari/.exec(navigator.userAgent) && !/Chrome/.exec(navigator.userAgent), |
|
2947 m = /(\d+\.\d+) Safari/.exec(navigator.userAgent), |
|
2948 safariVersion = m ? Number(m[1]) : 100; |
|
2949 |
|
2950 /* flowplayer() */ |
|
2951 var flowplayer = module.exports = function(fn, opts, callback) { |
|
2952 if (isFunction(fn)) return extensions.push(fn); |
|
2953 if (typeof fn == 'number' || typeof fn === 'undefined') return instances[fn || 0]; |
|
2954 if (fn.nodeType) { // Is an element |
|
2955 if (fn.getAttribute('data-flowplayer-instance-id') !== null) { // Already flowplayer instance |
|
2956 return instances[fn.getAttribute('data-flowplayer-instance-id')]; |
|
2957 } |
|
2958 if (!opts) return; // Can't initialize without data |
|
2959 return initializePlayer(fn, opts, callback); |
|
2960 } |
|
2961 if (fn.jquery) return flowplayer(fn[0], opts, callback); |
|
2962 if (typeof fn === 'string') { |
|
2963 var el = common.find(fn)[0]; |
|
2964 return el && flowplayer(el, opts, callback); |
|
2965 } |
|
2966 }; |
|
2967 |
|
2968 extend(flowplayer, { |
|
2969 |
|
2970 version: '6.0.3', |
|
2971 |
|
2972 engines: [], |
|
2973 |
|
2974 conf: {}, |
|
2975 |
|
2976 set: function(key, value) { |
|
2977 if (typeof key === 'string') flowplayer.conf[key] = value; |
|
2978 else extend(flowplayer.conf, key); |
|
2979 }, |
|
2980 |
|
2981 support: {}, |
|
2982 |
|
2983 defaults: { |
|
2984 |
|
2985 debug: supportLocalStorage ? !!localStorage.flowplayerDebug : false, |
|
2986 |
|
2987 // true = forced playback |
|
2988 disabled: false, |
|
2989 |
|
2990 fullscreen: window == window.top, |
|
2991 |
|
2992 // keyboard shortcuts |
|
2993 keyboard: true, |
|
2994 |
|
2995 // default aspect ratio |
|
2996 ratio: 9 / 16, |
|
2997 |
|
2998 adaptiveRatio: false, |
|
2999 |
|
3000 rtmp: 0, |
|
3001 |
|
3002 proxy: 'best', |
|
3003 |
|
3004 splash: false, |
|
3005 |
|
3006 live: false, |
|
3007 |
|
3008 swf: "//releases.flowplayer.org/6.0.3/flowplayer.swf", |
|
3009 swfHls: "//releases.flowplayer.org/6.0.3/flowplayerhls.swf", |
|
3010 |
|
3011 speeds: [0.25, 0.5, 1, 1.5, 2], |
|
3012 |
|
3013 tooltip: true, |
|
3014 |
|
3015 mouseoutTimeout: 5000, |
|
3016 |
|
3017 // initial volume level |
|
3018 volume: !supportLocalStorage ? 1 : localStorage.muted == "true" ? 0 : !isNaN(localStorage.volume) ? localStorage.volume || 1 : 1, |
|
3019 |
|
3020 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#error-codes |
|
3021 errors: [ |
|
3022 |
|
3023 // video exceptions |
|
3024 '', |
|
3025 'Video loading aborted', |
|
3026 'Network error', |
|
3027 'Video not properly encoded', |
|
3028 'Video file not found', |
|
3029 |
|
3030 // player exceptions |
|
3031 'Unsupported video', |
|
3032 'Skin not found', |
|
3033 'SWF file not found', |
|
3034 'Subtitles not found', |
|
3035 'Invalid RTMP URL', |
|
3036 'Unsupported video format. Try installing Adobe Flash.' |
|
3037 ], |
|
3038 errorUrls: ['','','','','','','','','','', |
|
3039 'http://get.adobe.com/flashplayer/' |
|
3040 ], |
|
3041 playlist: [], |
|
3042 |
|
3043 hlsFix: isSafari && safariVersion < 8 |
|
3044 |
|
3045 }, |
|
3046 // Expose utilities for plugins |
|
3047 bean: bean, |
|
3048 common: common, |
|
3049 extend: extend |
|
3050 |
|
3051 |
|
3052 |
|
3053 }); |
|
3054 |
|
3055 // keep track of players |
|
3056 var playerCount = 0; |
|
3057 |
|
3058 var URLResolver = _dereq_('./ext/resolve'); |
|
3059 |
|
3060 |
|
3061 |
|
3062 if (typeof window.jQuery !== 'undefined') { |
|
3063 var $ = window.jQuery; |
|
3064 // auto-install (any video tag with parent .flowplayer) |
|
3065 $(function() { |
|
3066 if (typeof $.fn.flowplayer == 'function') { |
|
3067 $('.flowplayer:has(video,script[type="application/json"])').flowplayer(); |
|
3068 } |
|
3069 }); |
|
3070 |
|
3071 // jQuery plugin |
|
3072 var videoTagConfig = function(videoTag) { |
|
3073 if (!videoTag.length) return {}; |
|
3074 var clip = videoTag.data() || {}, conf = {}; |
|
3075 $.each(['autoplay', 'loop', 'preload', 'poster'], function(i, key) { |
|
3076 var val = videoTag.attr(key); |
|
3077 if (val !== undefined && ['autoplay', 'poster'].indexOf(key) !== -1) conf[key] = val ? val : true; |
|
3078 else if (val !== undefined) clip[key] = val ? val : true; |
|
3079 }); |
|
3080 clip.subtitles = videoTag.find('track').map(function() { |
|
3081 var tr = $(this); |
|
3082 return { |
|
3083 src: tr.attr('src'), |
|
3084 kind: tr.attr('kind'), |
|
3085 label: tr.attr('label'), |
|
3086 srclang: tr.attr('srclang'), |
|
3087 'default': tr.prop('default') |
|
3088 }; |
|
3089 }).get(); |
|
3090 |
|
3091 clip.sources = (new URLResolver()).sourcesFromVideoTag(videoTag, $); |
|
3092 return extend(conf, {clip: clip}); |
|
3093 }; |
|
3094 $.fn.flowplayer = function(opts, callback) { |
|
3095 return this.each(function() { |
|
3096 if (typeof opts == 'string') opts = { swf: opts }; |
|
3097 if (isFunction(opts)) { callback = opts; opts = {}; } |
|
3098 var root = $(this), |
|
3099 scriptConf = root.find('script[type="application/json"]'), |
|
3100 confObject = scriptConf.length ? JSON.parse(scriptConf.text()) : videoTagConfig(root.find('video')), |
|
3101 conf = $.extend({}, opts || {}, confObject, root.data()); |
|
3102 var api = initializePlayer(this, conf, callback); |
|
3103 events.EVENTS.forEach(function(evName) { |
|
3104 api.on(evName + '.jquery', function(ev) { |
|
3105 root.trigger.call(root, ev.type, ev.detail && ev.detail.args); |
|
3106 }); |
|
3107 }); |
|
3108 root.data('flowplayer', api); |
|
3109 }); |
|
3110 }; |
|
3111 } |
|
3112 |
|
3113 function initializePlayer(element, opts, callback) { |
|
3114 if (opts && opts.embed) opts.embed = extend({}, flowplayer.defaults.embed, opts.embed); |
|
3115 |
|
3116 var root = element, |
|
3117 rootClasses = ClassList(root), |
|
3118 conf = extend({}, flowplayer.defaults, flowplayer.conf, opts), |
|
3119 storage = {}, |
|
3120 lastSeekPosition, |
|
3121 engine, |
|
3122 url, |
|
3123 urlResolver = new URLResolver(); |
|
3124 |
|
3125 rootClasses.add('is-loading'); |
|
3126 |
|
3127 try { |
|
3128 storage = supportLocalStorage ? window.localStorage : storage; |
|
3129 } catch(e) {} |
|
3130 |
|
3131 var isRTL = (root.currentStyle && root.currentStyle.direction === 'rtl') || |
|
3132 (window.getComputedStyle && window.getComputedStyle(root, null) !== null && window.getComputedStyle(root, null).getPropertyValue('direction') === 'rtl'); |
|
3133 |
|
3134 if (isRTL) rootClasses.add('is-rtl'); |
|
3135 |
|
3136 /*** API ***/ |
|
3137 var api = { |
|
3138 |
|
3139 // properties |
|
3140 conf: conf, |
|
3141 currentSpeed: 1, |
|
3142 volumeLevel: conf.muted ? 0 : typeof conf.volume === "undefined" ? storage.volume * 1 : conf.volume, |
|
3143 video: {}, |
|
3144 |
|
3145 // states |
|
3146 disabled: false, |
|
3147 finished: false, |
|
3148 loading: false, |
|
3149 muted: storage.muted == "true" || conf.muted, |
|
3150 paused: false, |
|
3151 playing: false, |
|
3152 ready: false, |
|
3153 splash: false, |
|
3154 rtl: isRTL, |
|
3155 |
|
3156 // methods |
|
3157 load: function(video, callback) { |
|
3158 |
|
3159 if (api.error || api.loading) return; |
|
3160 api.video = {}; |
|
3161 |
|
3162 api.finished = false; |
|
3163 |
|
3164 video = video || conf.clip; |
|
3165 |
|
3166 // resolve URL |
|
3167 video = extend({}, urlResolver.resolve(video, conf.clip.sources)); |
|
3168 if (api.playing || api.engine) video.autoplay = true; |
|
3169 var engineImpl = selectEngine(video); |
|
3170 if (!engineImpl) return api.trigger("error", [api, { code: flowplayer.support.flashVideo ? 5 : 10 }]); |
|
3171 if (!engineImpl.engineName) throw new Error('engineName property of factory should be exposed'); |
|
3172 if (!api.engine || engineImpl.engineName !== api.engine.engineName) { |
|
3173 api.ready = false; |
|
3174 if (api.engine) { |
|
3175 api.engine.unload(); |
|
3176 api.conf.autoplay = true; |
|
3177 } |
|
3178 engine = api.engine = engineImpl(api, root); |
|
3179 api.one('ready', function() { |
|
3180 engine.volume(api.volumeLevel); |
|
3181 }); |
|
3182 } |
|
3183 |
|
3184 extend(video, engine.pick(video.sources.filter(function(source) { // Filter out sources explicitely configured for some other engine |
|
3185 if (!source.engine) return true; |
|
3186 return source.engine === engine.engineName; |
|
3187 }))); |
|
3188 |
|
3189 if (video.src) { |
|
3190 video.src = common.createElement('a', {href: video.src}).href; |
|
3191 var e = api.trigger('load', [api, video, engine], true); |
|
3192 if (!e.defaultPrevented) { |
|
3193 engine.load(video); |
|
3194 |
|
3195 // callback |
|
3196 if (isFunction(video)) callback = video; |
|
3197 if (callback) api.one("ready", callback); |
|
3198 } else { |
|
3199 api.loading = false; |
|
3200 } |
|
3201 } |
|
3202 |
|
3203 return api; |
|
3204 }, |
|
3205 |
|
3206 pause: function(fn) { |
|
3207 if (api.ready && !api.seeking && !api.loading) { |
|
3208 engine.pause(); |
|
3209 api.one("pause", fn); |
|
3210 } |
|
3211 return api; |
|
3212 }, |
|
3213 |
|
3214 resume: function() { |
|
3215 |
|
3216 if (api.ready && api.paused) { |
|
3217 engine.resume(); |
|
3218 |
|
3219 // Firefox (+others?) does not fire "resume" after finish |
|
3220 if (api.finished) { |
|
3221 api.trigger("resume", [api]); |
|
3222 api.finished = false; |
|
3223 } |
|
3224 } |
|
3225 |
|
3226 return api; |
|
3227 }, |
|
3228 |
|
3229 toggle: function() { |
|
3230 return api.ready ? api.paused ? api.resume() : api.pause() : api.load(); |
|
3231 }, |
|
3232 |
|
3233 /* |
|
3234 seek(1.4) -> 1.4s time |
|
3235 seek(true) -> 10% forward |
|
3236 seek(false) -> 10% backward |
|
3237 */ |
|
3238 seek: function(time, callback) { |
|
3239 if (api.ready && !api.live) { |
|
3240 |
|
3241 if (typeof time == "boolean") { |
|
3242 var delta = api.video.duration * 0.1; |
|
3243 time = api.video.time + (time ? delta : -delta); |
|
3244 } |
|
3245 time = lastSeekPosition = Math.min(Math.max(time, 0), api.video.duration).toFixed(1); |
|
3246 var ev = api.trigger('beforeseek', [api, time], true); |
|
3247 if (!ev.defaultPrevented) { |
|
3248 engine.seek(time); |
|
3249 if (isFunction(callback)) api.one("seek", callback); |
|
3250 } else { |
|
3251 api.seeking = false; |
|
3252 common.toggleClass(root, 'is-seeking', api.seeking); // remove loading indicator |
|
3253 } |
|
3254 } |
|
3255 return api; |
|
3256 }, |
|
3257 |
|
3258 /* |
|
3259 seekTo(1) -> 10% |
|
3260 seekTo(2) -> 20% |
|
3261 seekTo(3) -> 30% |
|
3262 ... |
|
3263 seekTo() -> last position |
|
3264 */ |
|
3265 seekTo: function(position, fn) { |
|
3266 var time = position === undefined ? lastSeekPosition : api.video.duration * 0.1 * position; |
|
3267 return api.seek(time, fn); |
|
3268 }, |
|
3269 |
|
3270 mute: function(flag, skipStore) { |
|
3271 if (flag === undefined) flag = !api.muted; |
|
3272 if (!skipStore) { |
|
3273 storage.muted = api.muted = flag; |
|
3274 storage.volume = !isNaN(storage.volume) ? storage.volume : conf.volume; // make sure storage has volume |
|
3275 } |
|
3276 api.volume(flag ? 0 : storage.volume, true); |
|
3277 api.trigger("mute", [api, flag]); |
|
3278 return api; |
|
3279 }, |
|
3280 |
|
3281 volume: function(level, skipStore) { |
|
3282 if (api.ready) { |
|
3283 level = Math.min(Math.max(level, 0), 1); |
|
3284 if (!skipStore) storage.volume = level; |
|
3285 engine.volume(level); |
|
3286 } |
|
3287 |
|
3288 return api; |
|
3289 }, |
|
3290 |
|
3291 speed: function(val, callback) { |
|
3292 |
|
3293 if (api.ready) { |
|
3294 |
|
3295 // increase / decrease |
|
3296 if (typeof val == "boolean") { |
|
3297 val = conf.speeds[conf.speeds.indexOf(api.currentSpeed) + (val ? 1 : -1)] || api.currentSpeed; |
|
3298 } |
|
3299 |
|
3300 engine.speed(val); |
|
3301 if (callback) root.one("speed", callback); |
|
3302 } |
|
3303 |
|
3304 return api; |
|
3305 }, |
|
3306 |
|
3307 |
|
3308 stop: function() { |
|
3309 if (api.ready) { |
|
3310 api.pause(); |
|
3311 api.seek(0, function() { |
|
3312 api.trigger("stop"); |
|
3313 }); |
|
3314 } |
|
3315 return api; |
|
3316 }, |
|
3317 |
|
3318 unload: function() { |
|
3319 if (!rootClasses.contains("is-embedding")) { |
|
3320 |
|
3321 if (conf.splash) { |
|
3322 api.trigger("unload", [api]); |
|
3323 if (engine) engine.unload(); |
|
3324 } else { |
|
3325 api.stop(); |
|
3326 } |
|
3327 } |
|
3328 return api; |
|
3329 }, |
|
3330 |
|
3331 shutdown: function() { |
|
3332 api.unload(); |
|
3333 api.trigger('shutdown', [api]); |
|
3334 bean.off(root); |
|
3335 delete instances[root.getAttribute('data-flowplayer-instance-id')]; |
|
3336 }, |
|
3337 |
|
3338 disable: function(flag) { |
|
3339 if (flag === undefined) flag = !api.disabled; |
|
3340 |
|
3341 if (flag != api.disabled) { |
|
3342 api.disabled = flag; |
|
3343 api.trigger("disable", flag); |
|
3344 } |
|
3345 return api; |
|
3346 } |
|
3347 |
|
3348 }; |
|
3349 |
|
3350 api.conf = extend(api.conf, conf); |
|
3351 |
|
3352 /* event binding / unbinding */ |
|
3353 events(api); |
|
3354 |
|
3355 var selectEngine = function(clip) { |
|
3356 var engine; |
|
3357 var engines = flowplayer.engines; |
|
3358 if (conf.engine) { |
|
3359 var eng = engines.filter(function(e) { return e.engineName === conf.engine; })[0]; |
|
3360 if (eng && clip.sources.some(function(source) { |
|
3361 if (source.engine && source.engine !== eng.engineName) return false; |
|
3362 return eng.canPlay(source.type, api.conf); |
|
3363 })) return eng; |
|
3364 } |
|
3365 if (conf.enginePreference) engines = flowplayer.engines.filter(function(one) { return conf.enginePreference.indexOf(one.engineName) > -1; }).sort(function(a, b) { |
|
3366 return conf.enginePreference.indexOf(a.engineName) - conf.enginePreference.indexOf(b.engineName); |
|
3367 }); |
|
3368 clip.sources.some(function(source) { |
|
3369 var eng = engines.filter(function(engine) { |
|
3370 if (source.engine && source.engine !== engine.engineName) return false; |
|
3371 return engine.canPlay(source.type, api.conf); |
|
3372 }).shift(); |
|
3373 if (eng) engine = eng; |
|
3374 return !!eng; |
|
3375 }); |
|
3376 return engine; |
|
3377 }; |
|
3378 |
|
3379 /*** Behaviour ***/ |
|
3380 if (!root.getAttribute('data-flowplayer-instance-id')) { // Only bind once |
|
3381 root.setAttribute('data-flowplayer-instance-id', playerCount++); |
|
3382 |
|
3383 |
|
3384 api.on('boot', function() { |
|
3385 |
|
3386 // splash |
|
3387 if (conf.splash || rootClasses.contains("is-splash") || !flowplayer.support.firstframe) { |
|
3388 api.forcedSplash = !conf.splash && !rootClasses.contains("is-splash"); |
|
3389 api.splash = conf.autoplay = true; |
|
3390 if (!conf.splash) conf.splash = true; |
|
3391 rootClasses.add("is-splash"); |
|
3392 } |
|
3393 |
|
3394 if (conf.splash) common.find('video', root).forEach(common.removeNode); |
|
3395 |
|
3396 if (conf.live || rootClasses.contains('is-live')) { |
|
3397 api.live = conf.live = true; |
|
3398 rootClasses.add('is-live'); |
|
3399 } |
|
3400 |
|
3401 // extensions |
|
3402 extensions.forEach(function(e) { |
|
3403 e(api, root); |
|
3404 }); |
|
3405 |
|
3406 // instances |
|
3407 instances.push(api); |
|
3408 |
|
3409 // start |
|
3410 if (conf.splash) api.unload(); else api.load(); |
|
3411 |
|
3412 // disabled |
|
3413 if (conf.disabled) api.disable(); |
|
3414 |
|
3415 // initial callback |
|
3416 api.one("ready", callback); |
|
3417 |
|
3418 |
|
3419 }).on("load", function(e, api, video) { |
|
3420 |
|
3421 // unload others |
|
3422 if (conf.splash) { |
|
3423 common.find('.flowplayer.is-ready,.flowplayer.is-loading').forEach(function(el) { |
|
3424 var playerId = el.getAttribute('data-flowplayer-instance-id'); |
|
3425 if (playerId === root.getAttribute('data-flowplayer-instance-id')) return; |
|
3426 var a = instances[Number(playerId)]; |
|
3427 if (a && a.conf.splash) a.unload(); |
|
3428 }); |
|
3429 |
|
3430 } |
|
3431 |
|
3432 // loading |
|
3433 rootClasses.add("is-loading"); |
|
3434 api.loading = true; |
|
3435 |
|
3436 if (typeof video.live !== 'undefined') { |
|
3437 common.toggleClass(root, 'is-live', video.live); |
|
3438 api.live = video.live; |
|
3439 } |
|
3440 |
|
3441 |
|
3442 }).on("ready", function(e, api, video) { |
|
3443 video.time = 0; |
|
3444 api.video = video; |
|
3445 |
|
3446 rootClasses.remove("is-loading"); |
|
3447 api.loading = false; |
|
3448 |
|
3449 // saved state |
|
3450 if (api.muted) api.mute(true, true); |
|
3451 else api.volume(api.volumeLevel); |
|
3452 |
|
3453 // see https://github.com/flowplayer/flowplayer/issues/479 |
|
3454 |
|
3455 var hlsFix = api.conf.hlsFix && /mpegurl/i.exec(video.type); |
|
3456 common.toggleClass(root, 'hls-fix', !!hlsFix); |
|
3457 |
|
3458 }).on("unload", function(e) { |
|
3459 rootClasses.remove("is-loading"); |
|
3460 api.loading = false; |
|
3461 |
|
3462 |
|
3463 }).on("ready unload", function(e) { |
|
3464 var is_ready = e.type == "ready"; |
|
3465 common.toggleClass(root, 'is-splash', !is_ready); |
|
3466 common.toggleClass(root, 'is-ready', is_ready); |
|
3467 api.ready = is_ready; |
|
3468 api.splash = !is_ready; |
|
3469 |
|
3470 |
|
3471 }).on("progress", function(e, api, time) { |
|
3472 api.video.time = time; |
|
3473 |
|
3474 |
|
3475 }).on("speed", function(e, api, val) { |
|
3476 api.currentSpeed = val; |
|
3477 |
|
3478 }).on("volume", function(e, api, level) { |
|
3479 api.volumeLevel = Math.round(level * 100) / 100; |
|
3480 if (!api.muted) storage.volume = level; |
|
3481 else if (level) api.mute(false); |
|
3482 |
|
3483 |
|
3484 }).on("beforeseek seek", function(e) { |
|
3485 api.seeking = e.type == "beforeseek"; |
|
3486 common.toggleClass(root, 'is-seeking', api.seeking); |
|
3487 |
|
3488 }).on("ready pause resume unload finish stop", function(e, _api, video) { |
|
3489 |
|
3490 // PAUSED: pause / finish |
|
3491 api.paused = /pause|finish|unload|stop/.test(e.type); |
|
3492 api.paused = api.paused || e.type === 'ready' && !conf.autoplay && !api.playing; |
|
3493 |
|
3494 // the opposite |
|
3495 api.playing = !api.paused; |
|
3496 |
|
3497 // CSS classes |
|
3498 common.toggleClass(root, 'is-paused', api.paused); |
|
3499 common.toggleClass(root, 'is-playing', api.playing); |
|
3500 |
|
3501 // sanity check |
|
3502 if (!api.load.ed) api.pause(); |
|
3503 |
|
3504 }).on("finish", function(e) { |
|
3505 api.finished = true; |
|
3506 |
|
3507 }).on("error", function() { |
|
3508 }); |
|
3509 } |
|
3510 |
|
3511 // boot |
|
3512 api.trigger('boot', [api, root]); |
|
3513 return api; |
|
3514 } |
|
3515 |
|
3516 },{"./common":1,"./ext/events":8,"./ext/resolve":13,"bean":20,"class-list":22,"extend-object":26,"is-function":27}],19:[function(_dereq_,module,exports){ |
|
3517 //Flowplayer with extensions |
|
3518 |
|
3519 _dereq_('es5-shim'); |
|
3520 |
|
3521 var flowplayer = module.exports = _dereq_('./flowplayer'); |
|
3522 // |
|
3523 |
|
3524 //Support needed before engines |
|
3525 _dereq_('./ext/support'); |
|
3526 |
|
3527 //Engines |
|
3528 _dereq_('./engine/embed'); |
|
3529 _dereq_('./engine/html5'); |
|
3530 _dereq_('./engine/flash'); |
|
3531 |
|
3532 //Extensions |
|
3533 //require('./ext/slider'); //TODO enable |
|
3534 _dereq_('./ext/ui'); |
|
3535 _dereq_('./ext/keyboard'); |
|
3536 _dereq_('./ext/playlist'); |
|
3537 _dereq_('./ext/cuepoint'); |
|
3538 _dereq_('./ext/subtitle'); |
|
3539 _dereq_('./ext/analytics'); |
|
3540 _dereq_('./ext/embed'); |
|
3541 //Have to add fullscreen last |
|
3542 _dereq_('./ext/fullscreen'); |
|
3543 |
|
3544 _dereq_('./ext/mobile'); |
|
3545 flowplayer(function(e,o){function a(e){var o=document.createElement("a");return o.href=e,t.hostname(o.hostname)}var n=function(e,o){var a=e.className.split(" ");-1===a.indexOf(o)&&(e.className+=" "+o)},r=function(e){return"none"!==window.getComputedStyle(e).display},l=e.conf,t=flowplayer.common,i=t.createElement,d=l.swf.indexOf("flowplayer.org")&&l.e&&o.getAttribute("data-origin"),s=d?a(d):t.hostname(),p=(document,l.key);"file:"==location.protocol&&(s="localhost"),e.load.ed=1,l.hostname=s,l.origin=d||location.href,d&&n(o,"is-embedded"),"string"==typeof p&&(p=p.split(/,\s*/));var f=function(e,a){var n=i("a",{href:a,className:"fp-brand"});n.innerHTML=e,t.find(".fp-controls",o)[0].appendChild(n)};if(p&&"function"==typeof key_check&&key_check(p,s)){if(l.logo){var c=i("a",{href:d,className:"fp-logo"});l.embed&&l.embed.popup&&(c.target="_blank");var h=i("img",{src:l.logo});c.appendChild(h),o.appendChild(c)}l.brand&&d||l.brand&&l.brand.showOnOrigin?f(l.brand.text||l.brand,d||location.href):t.addClass(o,"no-brand")}else{f("flowplayer","http://flowplayer.org");var c=i("a",{href:"http://flowplayer.org"});o.appendChild(c);var y=i("div",{className:"fp-context-menu"},'<ul><li class="copyright">© 2015</li><li><a href="http://flowplayer.org">About Flowplayer</a></li><li><a href="http://flowplayer.org/license">GPL based license</a></li></ul>'),u=window.location.href.indexOf("localhost"),m=t.find(".fp-player",o)[0];7!==u&&(m||o).appendChild(y),e.on("pause resume finish unload ready",function(e,a){t.removeClass(o,"no-brand");var n=-1;if(a.video.src)for(var l=[["org","flowplayer","drive"],["org","flowplayer","my"]],i=0;i<l.length&&(n=a.video.src.indexOf("://"+l[i].reverse().join(".")),-1===n);i++);if((4===n||5===n)&&t.addClass(o,"no-brand"),/pause|resume/.test(e.type)&&"flash"!=a.engine.engineName&&4!=n&&5!=n){var d={display:"block",position:"absolute",left:"16px",bottom:"46px",zIndex:99999,width:"100px",height:"20px",backgroundImage:"url("+[".png","logo","/",".net",".cloudfront","d32wqyuo10o653","//"].reverse().join("")+")"};for(var s in d)d.hasOwnProperty(s)&&(c.style[s]=d[s]);a.load.ed=r(c)&&(7===u||y.parentNode==o||y.parentNode==m)&&!t.hasClass(o,"no-brand"),a.load.ed||a.pause()}else c.style.display="none"})}}); |
|
3546 |
|
3547 |
|
3548 },{"./engine/embed":2,"./engine/flash":3,"./engine/html5":4,"./ext/analytics":5,"./ext/cuepoint":6,"./ext/embed":7,"./ext/fullscreen":9,"./ext/keyboard":10,"./ext/mobile":11,"./ext/playlist":12,"./ext/subtitle":15,"./ext/support":16,"./ext/ui":17,"./flowplayer":18,"es5-shim":25}],20:[function(_dereq_,module,exports){ |
|
3549 /*! |
|
3550 * Bean - copyright (c) Jacob Thornton 2011-2012 |
|
3551 * https://github.com/fat/bean |
|
3552 * MIT license |
|
3553 */ |
|
3554 (function (name, context, definition) { |
|
3555 if (typeof module != 'undefined' && module.exports) module.exports = definition() |
|
3556 else if (typeof define == 'function' && define.amd) define(definition) |
|
3557 else context[name] = definition() |
|
3558 })('bean', this, function (name, context) { |
|
3559 name = name || 'bean' |
|
3560 context = context || this |
|
3561 |
|
3562 var win = window |
|
3563 , old = context[name] |
|
3564 , namespaceRegex = /[^\.]*(?=\..*)\.|.*/ |
|
3565 , nameRegex = /\..*/ |
|
3566 , addEvent = 'addEventListener' |
|
3567 , removeEvent = 'removeEventListener' |
|
3568 , doc = document || {} |
|
3569 , root = doc.documentElement || {} |
|
3570 , W3C_MODEL = root[addEvent] |
|
3571 , eventSupport = W3C_MODEL ? addEvent : 'attachEvent' |
|
3572 , ONE = {} // singleton for quick matching making add() do one() |
|
3573 |
|
3574 , slice = Array.prototype.slice |
|
3575 , str2arr = function (s, d) { return s.split(d || ' ') } |
|
3576 , isString = function (o) { return typeof o == 'string' } |
|
3577 , isFunction = function (o) { return typeof o == 'function' } |
|
3578 |
|
3579 // events that we consider to be 'native', anything not in this list will |
|
3580 // be treated as a custom event |
|
3581 , standardNativeEvents = |
|
3582 'click dblclick mouseup mousedown contextmenu ' + // mouse buttons |
|
3583 'mousewheel mousemultiwheel DOMMouseScroll ' + // mouse wheel |
|
3584 'mouseover mouseout mousemove selectstart selectend ' + // mouse movement |
|
3585 'keydown keypress keyup ' + // keyboard |
|
3586 'orientationchange ' + // mobile |
|
3587 'focus blur change reset select submit ' + // form elements |
|
3588 'load unload beforeunload resize move DOMContentLoaded ' + // window |
|
3589 'readystatechange message ' + // window |
|
3590 'error abort scroll ' // misc |
|
3591 // element.fireEvent('onXYZ'... is not forgiving if we try to fire an event |
|
3592 // that doesn't actually exist, so make sure we only do these on newer browsers |
|
3593 , w3cNativeEvents = |
|
3594 'show ' + // mouse buttons |
|
3595 'input invalid ' + // form elements |
|
3596 'touchstart touchmove touchend touchcancel ' + // touch |
|
3597 'gesturestart gesturechange gestureend ' + // gesture |
|
3598 'textinput ' + // TextEvent |
|
3599 'readystatechange pageshow pagehide popstate ' + // window |
|
3600 'hashchange offline online ' + // window |
|
3601 'afterprint beforeprint ' + // printing |
|
3602 'dragstart dragenter dragover dragleave drag drop dragend ' + // dnd |
|
3603 'loadstart progress suspend emptied stalled loadmetadata ' + // media |
|
3604 'loadeddata canplay canplaythrough playing waiting seeking ' + // media |
|
3605 'seeked ended durationchange timeupdate play pause ratechange ' + // media |
|
3606 'volumechange cuechange ' + // media |
|
3607 'checking noupdate downloading cached updateready obsolete ' // appcache |
|
3608 |
|
3609 // convert to a hash for quick lookups |
|
3610 , nativeEvents = (function (hash, events, i) { |
|
3611 for (i = 0; i < events.length; i++) events[i] && (hash[events[i]] = 1) |
|
3612 return hash |
|
3613 }({}, str2arr(standardNativeEvents + (W3C_MODEL ? w3cNativeEvents : '')))) |
|
3614 |
|
3615 // custom events are events that we *fake*, they are not provided natively but |
|
3616 // we can use native events to generate them |
|
3617 , customEvents = (function () { |
|
3618 var isAncestor = 'compareDocumentPosition' in root |
|
3619 ? function (element, container) { |
|
3620 return container.compareDocumentPosition && (container.compareDocumentPosition(element) & 16) === 16 |
|
3621 } |
|
3622 : 'contains' in root |
|
3623 ? function (element, container) { |
|
3624 container = container.nodeType === 9 || container === window ? root : container |
|
3625 return container !== element && container.contains(element) |
|
3626 } |
|
3627 : function (element, container) { |
|
3628 while (element = element.parentNode) if (element === container) return 1 |
|
3629 return 0 |
|
3630 } |
|
3631 , check = function (event) { |
|
3632 var related = event.relatedTarget |
|
3633 return !related |
|
3634 ? related == null |
|
3635 : (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString()) |
|
3636 && !isAncestor(related, this)) |
|
3637 } |
|
3638 |
|
3639 return { |
|
3640 mouseenter: { base: 'mouseover', condition: check } |
|
3641 , mouseleave: { base: 'mouseout', condition: check } |
|
3642 , mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' } |
|
3643 } |
|
3644 }()) |
|
3645 |
|
3646 // we provide a consistent Event object across browsers by taking the actual DOM |
|
3647 // event object and generating a new one from its properties. |
|
3648 , Event = (function () { |
|
3649 // a whitelist of properties (for different event types) tells us what to check for and copy |
|
3650 var commonProps = str2arr('altKey attrChange attrName bubbles cancelable ctrlKey currentTarget ' + |
|
3651 'detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey ' + |
|
3652 'srcElement target timeStamp type view which propertyName') |
|
3653 , mouseProps = commonProps.concat(str2arr('button buttons clientX clientY dataTransfer ' + |
|
3654 'fromElement offsetX offsetY pageX pageY screenX screenY toElement')) |
|
3655 , mouseWheelProps = mouseProps.concat(str2arr('wheelDelta wheelDeltaX wheelDeltaY wheelDeltaZ ' + |
|
3656 'axis')) // 'axis' is FF specific |
|
3657 , keyProps = commonProps.concat(str2arr('char charCode key keyCode keyIdentifier ' + |
|
3658 'keyLocation location')) |
|
3659 , textProps = commonProps.concat(str2arr('data')) |
|
3660 , touchProps = commonProps.concat(str2arr('touches targetTouches changedTouches scale rotation')) |
|
3661 , messageProps = commonProps.concat(str2arr('data origin source')) |
|
3662 , stateProps = commonProps.concat(str2arr('state')) |
|
3663 , overOutRegex = /over|out/ |
|
3664 // some event types need special handling and some need special properties, do that all here |
|
3665 , typeFixers = [ |
|
3666 { // key events |
|
3667 reg: /key/i |
|
3668 , fix: function (event, newEvent) { |
|
3669 newEvent.keyCode = event.keyCode || event.which |
|
3670 return keyProps |
|
3671 } |
|
3672 } |
|
3673 , { // mouse events |
|
3674 reg: /click|mouse(?!(.*wheel|scroll))|menu|drag|drop/i |
|
3675 , fix: function (event, newEvent, type) { |
|
3676 newEvent.rightClick = event.which === 3 || event.button === 2 |
|
3677 newEvent.pos = { x: 0, y: 0 } |
|
3678 if (event.pageX || event.pageY) { |
|
3679 newEvent.clientX = event.pageX |
|
3680 newEvent.clientY = event.pageY |
|
3681 } else if (event.clientX || event.clientY) { |
|
3682 newEvent.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft |
|
3683 newEvent.clientY = event.clientY + doc.body.scrollTop + root.scrollTop |
|
3684 } |
|
3685 if (overOutRegex.test(type)) { |
|
3686 newEvent.relatedTarget = event.relatedTarget |
|
3687 || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'] |
|
3688 } |
|
3689 return mouseProps |
|
3690 } |
|
3691 } |
|
3692 , { // mouse wheel events |
|
3693 reg: /mouse.*(wheel|scroll)/i |
|
3694 , fix: function () { return mouseWheelProps } |
|
3695 } |
|
3696 , { // TextEvent |
|
3697 reg: /^text/i |
|
3698 , fix: function () { return textProps } |
|
3699 } |
|
3700 , { // touch and gesture events |
|
3701 reg: /^touch|^gesture/i |
|
3702 , fix: function () { return touchProps } |
|
3703 } |
|
3704 , { // message events |
|
3705 reg: /^message$/i |
|
3706 , fix: function () { return messageProps } |
|
3707 } |
|
3708 , { // popstate events |
|
3709 reg: /^popstate$/i |
|
3710 , fix: function () { return stateProps } |
|
3711 } |
|
3712 , { // everything else |
|
3713 reg: /.*/ |
|
3714 , fix: function () { return commonProps } |
|
3715 } |
|
3716 ] |
|
3717 , typeFixerMap = {} // used to map event types to fixer functions (above), a basic cache mechanism |
|
3718 |
|
3719 , Event = function (event, element, isNative) { |
|
3720 if (!arguments.length) return |
|
3721 event = event || ((element.ownerDocument || element.document || element).parentWindow || win).event |
|
3722 this.originalEvent = event |
|
3723 this.isNative = isNative |
|
3724 this.isBean = true |
|
3725 |
|
3726 if (!event) return |
|
3727 |
|
3728 var type = event.type |
|
3729 , target = event.target || event.srcElement |
|
3730 , i, l, p, props, fixer |
|
3731 |
|
3732 this.target = target && target.nodeType === 3 ? target.parentNode : target |
|
3733 |
|
3734 if (isNative) { // we only need basic augmentation on custom events, the rest expensive & pointless |
|
3735 fixer = typeFixerMap[type] |
|
3736 if (!fixer) { // haven't encountered this event type before, map a fixer function for it |
|
3737 for (i = 0, l = typeFixers.length; i < l; i++) { |
|
3738 if (typeFixers[i].reg.test(type)) { // guaranteed to match at least one, last is .* |
|
3739 typeFixerMap[type] = fixer = typeFixers[i].fix |
|
3740 break |
|
3741 } |
|
3742 } |
|
3743 } |
|
3744 |
|
3745 props = fixer(event, this, type) |
|
3746 for (i = props.length; i--;) { |
|
3747 if (!((p = props[i]) in this) && p in event) this[p] = event[p] |
|
3748 } |
|
3749 } |
|
3750 } |
|
3751 |
|
3752 // preventDefault() and stopPropagation() are a consistent interface to those functions |
|
3753 // on the DOM, stop() is an alias for both of them together |
|
3754 Event.prototype.preventDefault = function () { |
|
3755 if (this.originalEvent.preventDefault) this.originalEvent.preventDefault() |
|
3756 else this.originalEvent.returnValue = false |
|
3757 } |
|
3758 Event.prototype.stopPropagation = function () { |
|
3759 if (this.originalEvent.stopPropagation) this.originalEvent.stopPropagation() |
|
3760 else this.originalEvent.cancelBubble = true |
|
3761 } |
|
3762 Event.prototype.stop = function () { |
|
3763 this.preventDefault() |
|
3764 this.stopPropagation() |
|
3765 this.stopped = true |
|
3766 } |
|
3767 // stopImmediatePropagation() has to be handled internally because we manage the event list for |
|
3768 // each element |
|
3769 // note that originalElement may be a Bean#Event object in some situations |
|
3770 Event.prototype.stopImmediatePropagation = function () { |
|
3771 if (this.originalEvent.stopImmediatePropagation) this.originalEvent.stopImmediatePropagation() |
|
3772 this.isImmediatePropagationStopped = function () { return true } |
|
3773 } |
|
3774 Event.prototype.isImmediatePropagationStopped = function () { |
|
3775 return this.originalEvent.isImmediatePropagationStopped && this.originalEvent.isImmediatePropagationStopped() |
|
3776 } |
|
3777 Event.prototype.clone = function (currentTarget) { |
|
3778 //TODO: this is ripe for optimisation, new events are *expensive* |
|
3779 // improving this will speed up delegated events |
|
3780 var ne = new Event(this, this.element, this.isNative) |
|
3781 ne.currentTarget = currentTarget |
|
3782 return ne |
|
3783 } |
|
3784 |
|
3785 return Event |
|
3786 }()) |
|
3787 |
|
3788 // if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both |
|
3789 , targetElement = function (element, isNative) { |
|
3790 return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element |
|
3791 } |
|
3792 |
|
3793 /** |
|
3794 * Bean maintains an internal registry for event listeners. We don't touch elements, objects |
|
3795 * or functions to identify them, instead we store everything in the registry. |
|
3796 * Each event listener has a RegEntry object, we have one 'registry' for the whole instance. |
|
3797 */ |
|
3798 , RegEntry = (function () { |
|
3799 // each handler is wrapped so we can handle delegation and custom events |
|
3800 var wrappedHandler = function (element, fn, condition, args) { |
|
3801 var call = function (event, eargs) { |
|
3802 return fn.apply(element, args ? slice.call(eargs, event ? 0 : 1).concat(args) : eargs) |
|
3803 } |
|
3804 , findTarget = function (event, eventElement) { |
|
3805 return fn.__beanDel ? fn.__beanDel.ft(event.target, element) : eventElement |
|
3806 } |
|
3807 , handler = condition |
|
3808 ? function (event) { |
|
3809 var target = findTarget(event, this) // deleated event |
|
3810 if (condition.apply(target, arguments)) { |
|
3811 if (event) event.currentTarget = target |
|
3812 return call(event, arguments) |
|
3813 } |
|
3814 } |
|
3815 : function (event) { |
|
3816 if (fn.__beanDel) event = event.clone(findTarget(event)) // delegated event, fix the fix |
|
3817 return call(event, arguments) |
|
3818 } |
|
3819 handler.__beanDel = fn.__beanDel |
|
3820 return handler |
|
3821 } |
|
3822 |
|
3823 , RegEntry = function (element, type, handler, original, namespaces, args, root) { |
|
3824 var customType = customEvents[type] |
|
3825 , isNative |
|
3826 |
|
3827 if (type == 'unload') { |
|
3828 // self clean-up |
|
3829 handler = once(removeListener, element, type, handler, original) |
|
3830 } |
|
3831 |
|
3832 if (customType) { |
|
3833 if (customType.condition) { |
|
3834 handler = wrappedHandler(element, handler, customType.condition, args) |
|
3835 } |
|
3836 type = customType.base || type |
|
3837 } |
|
3838 |
|
3839 this.isNative = isNative = nativeEvents[type] && !!element[eventSupport] |
|
3840 this.customType = !W3C_MODEL && !isNative && type |
|
3841 this.element = element |
|
3842 this.type = type |
|
3843 this.original = original |
|
3844 this.namespaces = namespaces |
|
3845 this.eventType = W3C_MODEL || isNative ? type : 'propertychange' |
|
3846 this.target = targetElement(element, isNative) |
|
3847 this[eventSupport] = !!this.target[eventSupport] |
|
3848 this.root = root |
|
3849 this.handler = wrappedHandler(element, handler, null, args) |
|
3850 } |
|
3851 |
|
3852 // given a list of namespaces, is our entry in any of them? |
|
3853 RegEntry.prototype.inNamespaces = function (checkNamespaces) { |
|
3854 var i, j, c = 0 |
|
3855 if (!checkNamespaces) return true |
|
3856 if (!this.namespaces) return false |
|
3857 for (i = checkNamespaces.length; i--;) { |
|
3858 for (j = this.namespaces.length; j--;) { |
|
3859 if (checkNamespaces[i] == this.namespaces[j]) c++ |
|
3860 } |
|
3861 } |
|
3862 return checkNamespaces.length === c |
|
3863 } |
|
3864 |
|
3865 // match by element, original fn (opt), handler fn (opt) |
|
3866 RegEntry.prototype.matches = function (checkElement, checkOriginal, checkHandler) { |
|
3867 return this.element === checkElement && |
|
3868 (!checkOriginal || this.original === checkOriginal) && |
|
3869 (!checkHandler || this.handler === checkHandler) |
|
3870 } |
|
3871 |
|
3872 return RegEntry |
|
3873 }()) |
|
3874 |
|
3875 , registry = (function () { |
|
3876 // our map stores arrays by event type, just because it's better than storing |
|
3877 // everything in a single array. |
|
3878 // uses '$' as a prefix for the keys for safety and 'r' as a special prefix for |
|
3879 // rootListeners so we can look them up fast |
|
3880 var map = {} |
|
3881 |
|
3882 // generic functional search of our registry for matching listeners, |
|
3883 // `fn` returns false to break out of the loop |
|
3884 , forAll = function (element, type, original, handler, root, fn) { |
|
3885 var pfx = root ? 'r' : '$' |
|
3886 if (!type || type == '*') { |
|
3887 // search the whole registry |
|
3888 for (var t in map) { |
|
3889 if (t.charAt(0) == pfx) { |
|
3890 forAll(element, t.substr(1), original, handler, root, fn) |
|
3891 } |
|
3892 } |
|
3893 } else { |
|
3894 var i = 0, l, list = map[pfx + type], all = element == '*' |
|
3895 if (!list) return |
|
3896 for (l = list.length; i < l; i++) { |
|
3897 if ((all || list[i].matches(element, original, handler)) && !fn(list[i], list, i, type)) return |
|
3898 } |
|
3899 } |
|
3900 } |
|
3901 |
|
3902 , has = function (element, type, original, root) { |
|
3903 // we're not using forAll here simply because it's a bit slower and this |
|
3904 // needs to be fast |
|
3905 var i, list = map[(root ? 'r' : '$') + type] |
|
3906 if (list) { |
|
3907 for (i = list.length; i--;) { |
|
3908 if (!list[i].root && list[i].matches(element, original, null)) return true |
|
3909 } |
|
3910 } |
|
3911 return false |
|
3912 } |
|
3913 |
|
3914 , get = function (element, type, original, root) { |
|
3915 var entries = [] |
|
3916 forAll(element, type, original, null, root, function (entry) { |
|
3917 return entries.push(entry) |
|
3918 }) |
|
3919 return entries |
|
3920 } |
|
3921 |
|
3922 , put = function (entry) { |
|
3923 var has = !entry.root && !this.has(entry.element, entry.type, null, false) |
|
3924 , key = (entry.root ? 'r' : '$') + entry.type |
|
3925 ;(map[key] || (map[key] = [])).push(entry) |
|
3926 return has |
|
3927 } |
|
3928 |
|
3929 , del = function (entry) { |
|
3930 forAll(entry.element, entry.type, null, entry.handler, entry.root, function (entry, list, i) { |
|
3931 list.splice(i, 1) |
|
3932 entry.removed = true |
|
3933 if (list.length === 0) delete map[(entry.root ? 'r' : '$') + entry.type] |
|
3934 return false |
|
3935 }) |
|
3936 } |
|
3937 |
|
3938 // dump all entries, used for onunload |
|
3939 , entries = function () { |
|
3940 var t, entries = [] |
|
3941 for (t in map) { |
|
3942 if (t.charAt(0) == '$') entries = entries.concat(map[t]) |
|
3943 } |
|
3944 return entries |
|
3945 } |
|
3946 |
|
3947 return { has: has, get: get, put: put, del: del, entries: entries } |
|
3948 }()) |
|
3949 |
|
3950 // we need a selector engine for delegated events, use querySelectorAll if it exists |
|
3951 // but for older browsers we need Qwery, Sizzle or similar |
|
3952 , selectorEngine |
|
3953 , setSelectorEngine = function (e) { |
|
3954 if (!arguments.length) { |
|
3955 selectorEngine = doc.querySelectorAll |
|
3956 ? function (s, r) { |
|
3957 return r.querySelectorAll(s) |
|
3958 } |
|
3959 : function () { |
|
3960 throw new Error('Bean: No selector engine installed') // eeek |
|
3961 } |
|
3962 } else { |
|
3963 selectorEngine = e |
|
3964 } |
|
3965 } |
|
3966 |
|
3967 // we attach this listener to each DOM event that we need to listen to, only once |
|
3968 // per event type per DOM element |
|
3969 , rootListener = function (event, type) { |
|
3970 if (!W3C_MODEL && type && event && event.propertyName != '_on' + type) return |
|
3971 |
|
3972 var listeners = registry.get(this, type || event.type, null, false) |
|
3973 , l = listeners.length |
|
3974 , i = 0 |
|
3975 |
|
3976 event = new Event(event, this, true) |
|
3977 if (type) event.type = type |
|
3978 |
|
3979 // iterate through all handlers registered for this type, calling them unless they have |
|
3980 // been removed by a previous handler or stopImmediatePropagation() has been called |
|
3981 for (; i < l && !event.isImmediatePropagationStopped(); i++) { |
|
3982 if (!listeners[i].removed) listeners[i].handler.call(this, event) |
|
3983 } |
|
3984 } |
|
3985 |
|
3986 // add and remove listeners to DOM elements |
|
3987 , listener = W3C_MODEL |
|
3988 ? function (element, type, add) { |
|
3989 // new browsers |
|
3990 element[add ? addEvent : removeEvent](type, rootListener, false) |
|
3991 } |
|
3992 : function (element, type, add, custom) { |
|
3993 // IE8 and below, use attachEvent/detachEvent and we have to piggy-back propertychange events |
|
3994 // to simulate event bubbling etc. |
|
3995 var entry |
|
3996 if (add) { |
|
3997 registry.put(entry = new RegEntry( |
|
3998 element |
|
3999 , custom || type |
|
4000 , function (event) { // handler |
|
4001 rootListener.call(element, event, custom) |
|
4002 } |
|
4003 , rootListener |
|
4004 , null |
|
4005 , null |
|
4006 , true // is root |
|
4007 )) |
|
4008 if (custom && element['_on' + custom] == null) element['_on' + custom] = 0 |
|
4009 entry.target.attachEvent('on' + entry.eventType, entry.handler) |
|
4010 } else { |
|
4011 entry = registry.get(element, custom || type, rootListener, true)[0] |
|
4012 if (entry) { |
|
4013 entry.target.detachEvent('on' + entry.eventType, entry.handler) |
|
4014 registry.del(entry) |
|
4015 } |
|
4016 } |
|
4017 } |
|
4018 |
|
4019 , once = function (rm, element, type, fn, originalFn) { |
|
4020 // wrap the handler in a handler that does a remove as well |
|
4021 return function () { |
|
4022 fn.apply(this, arguments) |
|
4023 rm(element, type, originalFn) |
|
4024 } |
|
4025 } |
|
4026 |
|
4027 , removeListener = function (element, orgType, handler, namespaces) { |
|
4028 var type = orgType && orgType.replace(nameRegex, '') |
|
4029 , handlers = registry.get(element, type, null, false) |
|
4030 , removed = {} |
|
4031 , i, l |
|
4032 |
|
4033 for (i = 0, l = handlers.length; i < l; i++) { |
|
4034 if ((!handler || handlers[i].original === handler) && handlers[i].inNamespaces(namespaces)) { |
|
4035 // TODO: this is problematic, we have a registry.get() and registry.del() that |
|
4036 // both do registry searches so we waste cycles doing this. Needs to be rolled into |
|
4037 // a single registry.forAll(fn) that removes while finding, but the catch is that |
|
4038 // we'll be splicing the arrays that we're iterating over. Needs extra tests to |
|
4039 // make sure we don't screw it up. @rvagg |
|
4040 registry.del(handlers[i]) |
|
4041 if (!removed[handlers[i].eventType] && handlers[i][eventSupport]) |
|
4042 removed[handlers[i].eventType] = { t: handlers[i].eventType, c: handlers[i].type } |
|
4043 } |
|
4044 } |
|
4045 // check each type/element for removed listeners and remove the rootListener where it's no longer needed |
|
4046 for (i in removed) { |
|
4047 if (!registry.has(element, removed[i].t, null, false)) { |
|
4048 // last listener of this type, remove the rootListener |
|
4049 listener(element, removed[i].t, false, removed[i].c) |
|
4050 } |
|
4051 } |
|
4052 } |
|
4053 |
|
4054 // set up a delegate helper using the given selector, wrap the handler function |
|
4055 , delegate = function (selector, fn) { |
|
4056 //TODO: findTarget (therefore $) is called twice, once for match and once for |
|
4057 // setting e.currentTarget, fix this so it's only needed once |
|
4058 var findTarget = function (target, root) { |
|
4059 var i, array = isString(selector) ? selectorEngine(selector, root) : selector |
|
4060 for (; target && target !== root; target = target.parentNode) { |
|
4061 for (i = array.length; i--;) { |
|
4062 if (array[i] === target) return target |
|
4063 } |
|
4064 } |
|
4065 } |
|
4066 , handler = function (e) { |
|
4067 var match = findTarget(e.target, this) |
|
4068 if (match) fn.apply(match, arguments) |
|
4069 } |
|
4070 |
|
4071 // __beanDel isn't pleasant but it's a private function, not exposed outside of Bean |
|
4072 handler.__beanDel = { |
|
4073 ft : findTarget // attach it here for customEvents to use too |
|
4074 , selector : selector |
|
4075 } |
|
4076 return handler |
|
4077 } |
|
4078 |
|
4079 , fireListener = W3C_MODEL ? function (isNative, type, element) { |
|
4080 // modern browsers, do a proper dispatchEvent() |
|
4081 var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents') |
|
4082 evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1) |
|
4083 element.dispatchEvent(evt) |
|
4084 } : function (isNative, type, element) { |
|
4085 // old browser use onpropertychange, just increment a custom property to trigger the event |
|
4086 element = targetElement(element, isNative) |
|
4087 isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++ |
|
4088 } |
|
4089 |
|
4090 /** |
|
4091 * Public API: off(), on(), add(), (remove()), one(), fire(), clone() |
|
4092 */ |
|
4093 |
|
4094 /** |
|
4095 * off(element[, eventType(s)[, handler ]]) |
|
4096 */ |
|
4097 , off = function (element, typeSpec, fn) { |
|
4098 var isTypeStr = isString(typeSpec) |
|
4099 , k, type, namespaces, i |
|
4100 |
|
4101 if (isTypeStr && typeSpec.indexOf(' ') > 0) { |
|
4102 // off(el, 't1 t2 t3', fn) or off(el, 't1 t2 t3') |
|
4103 typeSpec = str2arr(typeSpec) |
|
4104 for (i = typeSpec.length; i--;) |
|
4105 off(element, typeSpec[i], fn) |
|
4106 return element |
|
4107 } |
|
4108 |
|
4109 type = isTypeStr && typeSpec.replace(nameRegex, '') |
|
4110 if (type && customEvents[type]) type = customEvents[type].base |
|
4111 |
|
4112 if (!typeSpec || isTypeStr) { |
|
4113 // off(el) or off(el, t1.ns) or off(el, .ns) or off(el, .ns1.ns2.ns3) |
|
4114 if (namespaces = isTypeStr && typeSpec.replace(namespaceRegex, '')) namespaces = str2arr(namespaces, '.') |
|
4115 removeListener(element, type, fn, namespaces) |
|
4116 } else if (isFunction(typeSpec)) { |
|
4117 // off(el, fn) |
|
4118 removeListener(element, null, typeSpec) |
|
4119 } else { |
|
4120 // off(el, { t1: fn1, t2, fn2 }) |
|
4121 for (k in typeSpec) { |
|
4122 if (typeSpec.hasOwnProperty(k)) off(element, k, typeSpec[k]) |
|
4123 } |
|
4124 } |
|
4125 |
|
4126 return element |
|
4127 } |
|
4128 |
|
4129 /** |
|
4130 * on(element, eventType(s)[, selector], handler[, args ]) |
|
4131 */ |
|
4132 , on = function(element, events, selector, fn) { |
|
4133 var originalFn, type, types, i, args, entry, first |
|
4134 |
|
4135 //TODO: the undefined check means you can't pass an 'args' argument, fix this perhaps? |
|
4136 if (selector === undefined && typeof events == 'object') { |
|
4137 //TODO: this can't handle delegated events |
|
4138 for (type in events) { |
|
4139 if (events.hasOwnProperty(type)) { |
|
4140 on.call(this, element, type, events[type]) |
|
4141 } |
|
4142 } |
|
4143 return |
|
4144 } |
|
4145 |
|
4146 if (!isFunction(selector)) { |
|
4147 // delegated event |
|
4148 originalFn = fn |
|
4149 args = slice.call(arguments, 4) |
|
4150 fn = delegate(selector, originalFn, selectorEngine) |
|
4151 } else { |
|
4152 args = slice.call(arguments, 3) |
|
4153 fn = originalFn = selector |
|
4154 } |
|
4155 |
|
4156 types = str2arr(events) |
|
4157 |
|
4158 // special case for one(), wrap in a self-removing handler |
|
4159 if (this === ONE) { |
|
4160 fn = once(off, element, events, fn, originalFn) |
|
4161 } |
|
4162 |
|
4163 for (i = types.length; i--;) { |
|
4164 // add new handler to the registry and check if it's the first for this element/type |
|
4165 first = registry.put(entry = new RegEntry( |
|
4166 element |
|
4167 , types[i].replace(nameRegex, '') // event type |
|
4168 , fn |
|
4169 , originalFn |
|
4170 , str2arr(types[i].replace(namespaceRegex, ''), '.') // namespaces |
|
4171 , args |
|
4172 , false // not root |
|
4173 )) |
|
4174 if (entry[eventSupport] && first) { |
|
4175 // first event of this type on this element, add root listener |
|
4176 listener(element, entry.eventType, true, entry.customType) |
|
4177 } |
|
4178 } |
|
4179 |
|
4180 return element |
|
4181 } |
|
4182 |
|
4183 /** |
|
4184 * add(element[, selector], eventType(s), handler[, args ]) |
|
4185 * |
|
4186 * Deprecated: kept (for now) for backward-compatibility |
|
4187 */ |
|
4188 , add = function (element, events, fn, delfn) { |
|
4189 return on.apply( |
|
4190 null |
|
4191 , !isString(fn) |
|
4192 ? slice.call(arguments) |
|
4193 : [ element, fn, events, delfn ].concat(arguments.length > 3 ? slice.call(arguments, 5) : []) |
|
4194 ) |
|
4195 } |
|
4196 |
|
4197 /** |
|
4198 * one(element, eventType(s)[, selector], handler[, args ]) |
|
4199 */ |
|
4200 , one = function () { |
|
4201 return on.apply(ONE, arguments) |
|
4202 } |
|
4203 |
|
4204 /** |
|
4205 * fire(element, eventType(s)[, args ]) |
|
4206 * |
|
4207 * The optional 'args' argument must be an array, if no 'args' argument is provided |
|
4208 * then we can use the browser's DOM event system, otherwise we trigger handlers manually |
|
4209 */ |
|
4210 , fire = function (element, type, args) { |
|
4211 var types = str2arr(type) |
|
4212 , i, j, l, names, handlers |
|
4213 |
|
4214 for (i = types.length; i--;) { |
|
4215 type = types[i].replace(nameRegex, '') |
|
4216 if (names = types[i].replace(namespaceRegex, '')) names = str2arr(names, '.') |
|
4217 if (!names && !args && element[eventSupport]) { |
|
4218 fireListener(nativeEvents[type], type, element) |
|
4219 } else { |
|
4220 // non-native event, either because of a namespace, arguments or a non DOM element |
|
4221 // iterate over all listeners and manually 'fire' |
|
4222 handlers = registry.get(element, type, null, false) |
|
4223 args = [false].concat(args) |
|
4224 for (j = 0, l = handlers.length; j < l; j++) { |
|
4225 if (handlers[j].inNamespaces(names)) { |
|
4226 handlers[j].handler.apply(element, args) |
|
4227 } |
|
4228 } |
|
4229 } |
|
4230 } |
|
4231 return element |
|
4232 } |
|
4233 |
|
4234 /** |
|
4235 * clone(dstElement, srcElement[, eventType ]) |
|
4236 * |
|
4237 * TODO: perhaps for consistency we should allow the same flexibility in type specifiers? |
|
4238 */ |
|
4239 , clone = function (element, from, type) { |
|
4240 var handlers = registry.get(from, type, null, false) |
|
4241 , l = handlers.length |
|
4242 , i = 0 |
|
4243 , args, beanDel |
|
4244 |
|
4245 for (; i < l; i++) { |
|
4246 if (handlers[i].original) { |
|
4247 args = [ element, handlers[i].type ] |
|
4248 if (beanDel = handlers[i].handler.__beanDel) args.push(beanDel.selector) |
|
4249 args.push(handlers[i].original) |
|
4250 on.apply(null, args) |
|
4251 } |
|
4252 } |
|
4253 return element |
|
4254 } |
|
4255 |
|
4256 , bean = { |
|
4257 'on' : on |
|
4258 , 'add' : add |
|
4259 , 'one' : one |
|
4260 , 'off' : off |
|
4261 , 'remove' : off |
|
4262 , 'clone' : clone |
|
4263 , 'fire' : fire |
|
4264 , 'Event' : Event |
|
4265 , 'setSelectorEngine' : setSelectorEngine |
|
4266 , 'noConflict' : function () { |
|
4267 context[name] = old |
|
4268 return this |
|
4269 } |
|
4270 } |
|
4271 |
|
4272 // for IE, clean up on unload to avoid leaks |
|
4273 if (win.attachEvent) { |
|
4274 var cleanup = function () { |
|
4275 var i, entries = registry.entries() |
|
4276 for (i in entries) { |
|
4277 if (entries[i].type && entries[i].type !== 'unload') off(entries[i].element, entries[i].type) |
|
4278 } |
|
4279 win.detachEvent('onunload', cleanup) |
|
4280 win.CollectGarbage && win.CollectGarbage() |
|
4281 } |
|
4282 win.attachEvent('onunload', cleanup) |
|
4283 } |
|
4284 |
|
4285 // initialize selector engine to internal default (qSA or throw Error) |
|
4286 setSelectorEngine() |
|
4287 |
|
4288 return bean |
|
4289 }); |
|
4290 |
|
4291 },{}],21:[function(_dereq_,module,exports){ |
|
4292 (function (global){ |
|
4293 /*! http://mths.be/punycode v1.2.4 by @mathias */ |
|
4294 ;(function(root) { |
|
4295 |
|
4296 /** Detect free variables */ |
|
4297 var freeExports = typeof exports == 'object' && exports; |
|
4298 var freeModule = typeof module == 'object' && module && |
|
4299 module.exports == freeExports && module; |
|
4300 var freeGlobal = typeof global == 'object' && global; |
|
4301 if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { |
|
4302 root = freeGlobal; |
|
4303 } |
|
4304 |
|
4305 /** |
|
4306 * The `punycode` object. |
|
4307 * @name punycode |
|
4308 * @type Object |
|
4309 */ |
|
4310 var punycode, |
|
4311 |
|
4312 /** Highest positive signed 32-bit float value */ |
|
4313 maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 |
|
4314 |
|
4315 /** Bootstring parameters */ |
|
4316 base = 36, |
|
4317 tMin = 1, |
|
4318 tMax = 26, |
|
4319 skew = 38, |
|
4320 damp = 700, |
|
4321 initialBias = 72, |
|
4322 initialN = 128, // 0x80 |
|
4323 delimiter = '-', // '\x2D' |
|
4324 |
|
4325 /** Regular expressions */ |
|
4326 regexPunycode = /^xn--/, |
|
4327 regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars |
|
4328 regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators |
|
4329 |
|
4330 /** Error messages */ |
|
4331 errors = { |
|
4332 'overflow': 'Overflow: input needs wider integers to process', |
|
4333 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', |
|
4334 'invalid-input': 'Invalid input' |
|
4335 }, |
|
4336 |
|
4337 /** Convenience shortcuts */ |
|
4338 baseMinusTMin = base - tMin, |
|
4339 floor = Math.floor, |
|
4340 stringFromCharCode = String.fromCharCode, |
|
4341 |
|
4342 /** Temporary variable */ |
|
4343 key; |
|
4344 |
|
4345 /*--------------------------------------------------------------------------*/ |
|
4346 |
|
4347 /** |
|
4348 * A generic error utility function. |
|
4349 * @private |
|
4350 * @param {String} type The error type. |
|
4351 * @returns {Error} Throws a `RangeError` with the applicable error message. |
|
4352 */ |
|
4353 function error(type) { |
|
4354 throw RangeError(errors[type]); |
|
4355 } |
|
4356 |
|
4357 /** |
|
4358 * A generic `Array#map` utility function. |
|
4359 * @private |
|
4360 * @param {Array} array The array to iterate over. |
|
4361 * @param {Function} callback The function that gets called for every array |
|
4362 * item. |
|
4363 * @returns {Array} A new array of values returned by the callback function. |
|
4364 */ |
|
4365 function map(array, fn) { |
|
4366 var length = array.length; |
|
4367 while (length--) { |
|
4368 array[length] = fn(array[length]); |
|
4369 } |
|
4370 return array; |
|
4371 } |
|
4372 |
|
4373 /** |
|
4374 * A simple `Array#map`-like wrapper to work with domain name strings. |
|
4375 * @private |
|
4376 * @param {String} domain The domain name. |
|
4377 * @param {Function} callback The function that gets called for every |
|
4378 * character. |
|
4379 * @returns {Array} A new string of characters returned by the callback |
|
4380 * function. |
|
4381 */ |
|
4382 function mapDomain(string, fn) { |
|
4383 return map(string.split(regexSeparators), fn).join('.'); |
|
4384 } |
|
4385 |
|
4386 /** |
|
4387 * Creates an array containing the numeric code points of each Unicode |
|
4388 * character in the string. While JavaScript uses UCS-2 internally, |
|
4389 * this function will convert a pair of surrogate halves (each of which |
|
4390 * UCS-2 exposes as separate characters) into a single code point, |
|
4391 * matching UTF-16. |
|
4392 * @see `punycode.ucs2.encode` |
|
4393 * @see <http://mathiasbynens.be/notes/javascript-encoding> |
|
4394 * @memberOf punycode.ucs2 |
|
4395 * @name decode |
|
4396 * @param {String} string The Unicode input string (UCS-2). |
|
4397 * @returns {Array} The new array of code points. |
|
4398 */ |
|
4399 function ucs2decode(string) { |
|
4400 var output = [], |
|
4401 counter = 0, |
|
4402 length = string.length, |
|
4403 value, |
|
4404 extra; |
|
4405 while (counter < length) { |
|
4406 value = string.charCodeAt(counter++); |
|
4407 if (value >= 0xD800 && value <= 0xDBFF && counter < length) { |
|
4408 // high surrogate, and there is a next character |
|
4409 extra = string.charCodeAt(counter++); |
|
4410 if ((extra & 0xFC00) == 0xDC00) { // low surrogate |
|
4411 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); |
|
4412 } else { |
|
4413 // unmatched surrogate; only append this code unit, in case the next |
|
4414 // code unit is the high surrogate of a surrogate pair |
|
4415 output.push(value); |
|
4416 counter--; |
|
4417 } |
|
4418 } else { |
|
4419 output.push(value); |
|
4420 } |
|
4421 } |
|
4422 return output; |
|
4423 } |
|
4424 |
|
4425 /** |
|
4426 * Creates a string based on an array of numeric code points. |
|
4427 * @see `punycode.ucs2.decode` |
|
4428 * @memberOf punycode.ucs2 |
|
4429 * @name encode |
|
4430 * @param {Array} codePoints The array of numeric code points. |
|
4431 * @returns {String} The new Unicode string (UCS-2). |
|
4432 */ |
|
4433 function ucs2encode(array) { |
|
4434 return map(array, function(value) { |
|
4435 var output = ''; |
|
4436 if (value > 0xFFFF) { |
|
4437 value -= 0x10000; |
|
4438 output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); |
|
4439 value = 0xDC00 | value & 0x3FF; |
|
4440 } |
|
4441 output += stringFromCharCode(value); |
|
4442 return output; |
|
4443 }).join(''); |
|
4444 } |
|
4445 |
|
4446 /** |
|
4447 * Converts a basic code point into a digit/integer. |
|
4448 * @see `digitToBasic()` |
|
4449 * @private |
|
4450 * @param {Number} codePoint The basic numeric code point value. |
|
4451 * @returns {Number} The numeric value of a basic code point (for use in |
|
4452 * representing integers) in the range `0` to `base - 1`, or `base` if |
|
4453 * the code point does not represent a value. |
|
4454 */ |
|
4455 function basicToDigit(codePoint) { |
|
4456 if (codePoint - 48 < 10) { |
|
4457 return codePoint - 22; |
|
4458 } |
|
4459 if (codePoint - 65 < 26) { |
|
4460 return codePoint - 65; |
|
4461 } |
|
4462 if (codePoint - 97 < 26) { |
|
4463 return codePoint - 97; |
|
4464 } |
|
4465 return base; |
|
4466 } |
|
4467 |
|
4468 /** |
|
4469 * Converts a digit/integer into a basic code point. |
|
4470 * @see `basicToDigit()` |
|
4471 * @private |
|
4472 * @param {Number} digit The numeric value of a basic code point. |
|
4473 * @returns {Number} The basic code point whose value (when used for |
|
4474 * representing integers) is `digit`, which needs to be in the range |
|
4475 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is |
|
4476 * used; else, the lowercase form is used. The behavior is undefined |
|
4477 * if `flag` is non-zero and `digit` has no uppercase form. |
|
4478 */ |
|
4479 function digitToBasic(digit, flag) { |
|
4480 // 0..25 map to ASCII a..z or A..Z |
|
4481 // 26..35 map to ASCII 0..9 |
|
4482 return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); |
|
4483 } |
|
4484 |
|
4485 /** |
|
4486 * Bias adaptation function as per section 3.4 of RFC 3492. |
|
4487 * http://tools.ietf.org/html/rfc3492#section-3.4 |
|
4488 * @private |
|
4489 */ |
|
4490 function adapt(delta, numPoints, firstTime) { |
|
4491 var k = 0; |
|
4492 delta = firstTime ? floor(delta / damp) : delta >> 1; |
|
4493 delta += floor(delta / numPoints); |
|
4494 for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { |
|
4495 delta = floor(delta / baseMinusTMin); |
|
4496 } |
|
4497 return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); |
|
4498 } |
|
4499 |
|
4500 /** |
|
4501 * Converts a Punycode string of ASCII-only symbols to a string of Unicode |
|
4502 * symbols. |
|
4503 * @memberOf punycode |
|
4504 * @param {String} input The Punycode string of ASCII-only symbols. |
|
4505 * @returns {String} The resulting string of Unicode symbols. |
|
4506 */ |
|
4507 function decode(input) { |
|
4508 // Don't use UCS-2 |
|
4509 var output = [], |
|
4510 inputLength = input.length, |
|
4511 out, |
|
4512 i = 0, |
|
4513 n = initialN, |
|
4514 bias = initialBias, |
|
4515 basic, |
|
4516 j, |
|
4517 index, |
|
4518 oldi, |
|
4519 w, |
|
4520 k, |
|
4521 digit, |
|
4522 t, |
|
4523 /** Cached calculation results */ |
|
4524 baseMinusT; |
|
4525 |
|
4526 // Handle the basic code points: let `basic` be the number of input code |
|
4527 // points before the last delimiter, or `0` if there is none, then copy |
|
4528 // the first basic code points to the output. |
|
4529 |
|
4530 basic = input.lastIndexOf(delimiter); |
|
4531 if (basic < 0) { |
|
4532 basic = 0; |
|
4533 } |
|
4534 |
|
4535 for (j = 0; j < basic; ++j) { |
|
4536 // if it's not a basic code point |
|
4537 if (input.charCodeAt(j) >= 0x80) { |
|
4538 error('not-basic'); |
|
4539 } |
|
4540 output.push(input.charCodeAt(j)); |
|
4541 } |
|
4542 |
|
4543 // Main decoding loop: start just after the last delimiter if any basic code |
|
4544 // points were copied; start at the beginning otherwise. |
|
4545 |
|
4546 for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { |
|
4547 |
|
4548 // `index` is the index of the next character to be consumed. |
|
4549 // Decode a generalized variable-length integer into `delta`, |
|
4550 // which gets added to `i`. The overflow checking is easier |
|
4551 // if we increase `i` as we go, then subtract off its starting |
|
4552 // value at the end to obtain `delta`. |
|
4553 for (oldi = i, w = 1, k = base; /* no condition */; k += base) { |
|
4554 |
|
4555 if (index >= inputLength) { |
|
4556 error('invalid-input'); |
|
4557 } |
|
4558 |
|
4559 digit = basicToDigit(input.charCodeAt(index++)); |
|
4560 |
|
4561 if (digit >= base || digit > floor((maxInt - i) / w)) { |
|
4562 error('overflow'); |
|
4563 } |
|
4564 |
|
4565 i += digit * w; |
|
4566 t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); |
|
4567 |
|
4568 if (digit < t) { |
|
4569 break; |
|
4570 } |
|
4571 |
|
4572 baseMinusT = base - t; |
|
4573 if (w > floor(maxInt / baseMinusT)) { |
|
4574 error('overflow'); |
|
4575 } |
|
4576 |
|
4577 w *= baseMinusT; |
|
4578 |
|
4579 } |
|
4580 |
|
4581 out = output.length + 1; |
|
4582 bias = adapt(i - oldi, out, oldi == 0); |
|
4583 |
|
4584 // `i` was supposed to wrap around from `out` to `0`, |
|
4585 // incrementing `n` each time, so we'll fix that now: |
|
4586 if (floor(i / out) > maxInt - n) { |
|
4587 error('overflow'); |
|
4588 } |
|
4589 |
|
4590 n += floor(i / out); |
|
4591 i %= out; |
|
4592 |
|
4593 // Insert `n` at position `i` of the output |
|
4594 output.splice(i++, 0, n); |
|
4595 |
|
4596 } |
|
4597 |
|
4598 return ucs2encode(output); |
|
4599 } |
|
4600 |
|
4601 /** |
|
4602 * Converts a string of Unicode symbols to a Punycode string of ASCII-only |
|
4603 * symbols. |
|
4604 * @memberOf punycode |
|
4605 * @param {String} input The string of Unicode symbols. |
|
4606 * @returns {String} The resulting Punycode string of ASCII-only symbols. |
|
4607 */ |
|
4608 function encode(input) { |
|
4609 var n, |
|
4610 delta, |
|
4611 handledCPCount, |
|
4612 basicLength, |
|
4613 bias, |
|
4614 j, |
|
4615 m, |
|
4616 q, |
|
4617 k, |
|
4618 t, |
|
4619 currentValue, |
|
4620 output = [], |
|
4621 /** `inputLength` will hold the number of code points in `input`. */ |
|
4622 inputLength, |
|
4623 /** Cached calculation results */ |
|
4624 handledCPCountPlusOne, |
|
4625 baseMinusT, |
|
4626 qMinusT; |
|
4627 |
|
4628 // Convert the input in UCS-2 to Unicode |
|
4629 input = ucs2decode(input); |
|
4630 |
|
4631 // Cache the length |
|
4632 inputLength = input.length; |
|
4633 |
|
4634 // Initialize the state |
|
4635 n = initialN; |
|
4636 delta = 0; |
|
4637 bias = initialBias; |
|
4638 |
|
4639 // Handle the basic code points |
|
4640 for (j = 0; j < inputLength; ++j) { |
|
4641 currentValue = input[j]; |
|
4642 if (currentValue < 0x80) { |
|
4643 output.push(stringFromCharCode(currentValue)); |
|
4644 } |
|
4645 } |
|
4646 |
|
4647 handledCPCount = basicLength = output.length; |
|
4648 |
|
4649 // `handledCPCount` is the number of code points that have been handled; |
|
4650 // `basicLength` is the number of basic code points. |
|
4651 |
|
4652 // Finish the basic string - if it is not empty - with a delimiter |
|
4653 if (basicLength) { |
|
4654 output.push(delimiter); |
|
4655 } |
|
4656 |
|
4657 // Main encoding loop: |
|
4658 while (handledCPCount < inputLength) { |
|
4659 |
|
4660 // All non-basic code points < n have been handled already. Find the next |
|
4661 // larger one: |
|
4662 for (m = maxInt, j = 0; j < inputLength; ++j) { |
|
4663 currentValue = input[j]; |
|
4664 if (currentValue >= n && currentValue < m) { |
|
4665 m = currentValue; |
|
4666 } |
|
4667 } |
|
4668 |
|
4669 // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, |
|
4670 // but guard against overflow |
|
4671 handledCPCountPlusOne = handledCPCount + 1; |
|
4672 if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { |
|
4673 error('overflow'); |
|
4674 } |
|
4675 |
|
4676 delta += (m - n) * handledCPCountPlusOne; |
|
4677 n = m; |
|
4678 |
|
4679 for (j = 0; j < inputLength; ++j) { |
|
4680 currentValue = input[j]; |
|
4681 |
|
4682 if (currentValue < n && ++delta > maxInt) { |
|
4683 error('overflow'); |
|
4684 } |
|
4685 |
|
4686 if (currentValue == n) { |
|
4687 // Represent delta as a generalized variable-length integer |
|
4688 for (q = delta, k = base; /* no condition */; k += base) { |
|
4689 t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); |
|
4690 if (q < t) { |
|
4691 break; |
|
4692 } |
|
4693 qMinusT = q - t; |
|
4694 baseMinusT = base - t; |
|
4695 output.push( |
|
4696 stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) |
|
4697 ); |
|
4698 q = floor(qMinusT / baseMinusT); |
|
4699 } |
|
4700 |
|
4701 output.push(stringFromCharCode(digitToBasic(q, 0))); |
|
4702 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); |
|
4703 delta = 0; |
|
4704 ++handledCPCount; |
|
4705 } |
|
4706 } |
|
4707 |
|
4708 ++delta; |
|
4709 ++n; |
|
4710 |
|
4711 } |
|
4712 return output.join(''); |
|
4713 } |
|
4714 |
|
4715 /** |
|
4716 * Converts a Punycode string representing a domain name to Unicode. Only the |
|
4717 * Punycoded parts of the domain name will be converted, i.e. it doesn't |
|
4718 * matter if you call it on a string that has already been converted to |
|
4719 * Unicode. |
|
4720 * @memberOf punycode |
|
4721 * @param {String} domain The Punycode domain name to convert to Unicode. |
|
4722 * @returns {String} The Unicode representation of the given Punycode |
|
4723 * string. |
|
4724 */ |
|
4725 function toUnicode(domain) { |
|
4726 return mapDomain(domain, function(string) { |
|
4727 return regexPunycode.test(string) |
|
4728 ? decode(string.slice(4).toLowerCase()) |
|
4729 : string; |
|
4730 }); |
|
4731 } |
|
4732 |
|
4733 /** |
|
4734 * Converts a Unicode string representing a domain name to Punycode. Only the |
|
4735 * non-ASCII parts of the domain name will be converted, i.e. it doesn't |
|
4736 * matter if you call it with a domain that's already in ASCII. |
|
4737 * @memberOf punycode |
|
4738 * @param {String} domain The domain name to convert, as a Unicode string. |
|
4739 * @returns {String} The Punycode representation of the given domain name. |
|
4740 */ |
|
4741 function toASCII(domain) { |
|
4742 return mapDomain(domain, function(string) { |
|
4743 return regexNonASCII.test(string) |
|
4744 ? 'xn--' + encode(string) |
|
4745 : string; |
|
4746 }); |
|
4747 } |
|
4748 |
|
4749 /*--------------------------------------------------------------------------*/ |
|
4750 |
|
4751 /** Define the public API */ |
|
4752 punycode = { |
|
4753 /** |
|
4754 * A string representing the current Punycode.js version number. |
|
4755 * @memberOf punycode |
|
4756 * @type String |
|
4757 */ |
|
4758 'version': '1.2.4', |
|
4759 /** |
|
4760 * An object of methods to convert from JavaScript's internal character |
|
4761 * representation (UCS-2) to Unicode code points, and back. |
|
4762 * @see <http://mathiasbynens.be/notes/javascript-encoding> |
|
4763 * @memberOf punycode |
|
4764 * @type Object |
|
4765 */ |
|
4766 'ucs2': { |
|
4767 'decode': ucs2decode, |
|
4768 'encode': ucs2encode |
|
4769 }, |
|
4770 'decode': decode, |
|
4771 'encode': encode, |
|
4772 'toASCII': toASCII, |
|
4773 'toUnicode': toUnicode |
|
4774 }; |
|
4775 |
|
4776 /** Expose `punycode` */ |
|
4777 // Some AMD build optimizers, like r.js, check for specific condition patterns |
|
4778 // like the following: |
|
4779 if ( |
|
4780 typeof define == 'function' && |
|
4781 typeof define.amd == 'object' && |
|
4782 define.amd |
|
4783 ) { |
|
4784 define('punycode', function() { |
|
4785 return punycode; |
|
4786 }); |
|
4787 } else if (freeExports && !freeExports.nodeType) { |
|
4788 if (freeModule) { // in Node.js or RingoJS v0.8.0+ |
|
4789 freeModule.exports = punycode; |
|
4790 } else { // in Narwhal or RingoJS v0.7.0- |
|
4791 for (key in punycode) { |
|
4792 punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); |
|
4793 } |
|
4794 } |
|
4795 } else { // in Rhino or a web browser |
|
4796 root.punycode = punycode; |
|
4797 } |
|
4798 |
|
4799 }(this)); |
|
4800 |
|
4801 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
|
4802 },{}],22:[function(_dereq_,module,exports){ |
|
4803 // contains, add, remove, toggle |
|
4804 var indexof = _dereq_('indexof') |
|
4805 |
|
4806 module.exports = ClassList |
|
4807 |
|
4808 function ClassList(elem) { |
|
4809 var cl = elem.classList |
|
4810 |
|
4811 if (cl) { |
|
4812 return cl |
|
4813 } |
|
4814 |
|
4815 var classList = { |
|
4816 add: add |
|
4817 , remove: remove |
|
4818 , contains: contains |
|
4819 , toggle: toggle |
|
4820 , toString: $toString |
|
4821 , length: 0 |
|
4822 , item: item |
|
4823 } |
|
4824 |
|
4825 return classList |
|
4826 |
|
4827 function add(token) { |
|
4828 var list = getTokens() |
|
4829 if (indexof(list, token) > -1) { |
|
4830 return |
|
4831 } |
|
4832 list.push(token) |
|
4833 setTokens(list) |
|
4834 } |
|
4835 |
|
4836 function remove(token) { |
|
4837 var list = getTokens() |
|
4838 , index = indexof(list, token) |
|
4839 |
|
4840 if (index === -1) { |
|
4841 return |
|
4842 } |
|
4843 |
|
4844 list.splice(index, 1) |
|
4845 setTokens(list) |
|
4846 } |
|
4847 |
|
4848 function contains(token) { |
|
4849 return indexof(getTokens(), token) > -1 |
|
4850 } |
|
4851 |
|
4852 function toggle(token) { |
|
4853 if (contains(token)) { |
|
4854 remove(token) |
|
4855 return false |
|
4856 } else { |
|
4857 add(token) |
|
4858 return true |
|
4859 } |
|
4860 } |
|
4861 |
|
4862 function $toString() { |
|
4863 return elem.className |
|
4864 } |
|
4865 |
|
4866 function item(index) { |
|
4867 var tokens = getTokens() |
|
4868 return tokens[index] || null |
|
4869 } |
|
4870 |
|
4871 function getTokens() { |
|
4872 var className = elem.className |
|
4873 |
|
4874 return filter(className.split(" "), isTruthy) |
|
4875 } |
|
4876 |
|
4877 function setTokens(list) { |
|
4878 var length = list.length |
|
4879 |
|
4880 elem.className = list.join(" ") |
|
4881 classList.length = length |
|
4882 |
|
4883 for (var i = 0; i < list.length; i++) { |
|
4884 classList[i] = list[i] |
|
4885 } |
|
4886 |
|
4887 delete list[length] |
|
4888 } |
|
4889 } |
|
4890 |
|
4891 function filter (arr, fn) { |
|
4892 var ret = [] |
|
4893 for (var i = 0; i < arr.length; i++) { |
|
4894 if (fn(arr[i])) ret.push(arr[i]) |
|
4895 } |
|
4896 return ret |
|
4897 } |
|
4898 |
|
4899 function isTruthy(value) { |
|
4900 return !!value |
|
4901 } |
|
4902 |
|
4903 },{"indexof":23}],23:[function(_dereq_,module,exports){ |
|
4904 |
|
4905 var indexOf = [].indexOf; |
|
4906 |
|
4907 module.exports = function(arr, obj){ |
|
4908 if (indexOf) return arr.indexOf(obj); |
|
4909 for (var i = 0; i < arr.length; ++i) { |
|
4910 if (arr[i] === obj) return i; |
|
4911 } |
|
4912 return -1; |
|
4913 }; |
|
4914 },{}],24:[function(_dereq_,module,exports){ |
|
4915 // DEV: We don't use var but favor parameters since these play nicer with minification |
|
4916 function computedStyle(el, prop, getComputedStyle, style) { |
|
4917 getComputedStyle = window.getComputedStyle; |
|
4918 style = |
|
4919 // If we have getComputedStyle |
|
4920 getComputedStyle ? |
|
4921 // Query it |
|
4922 // TODO: From CSS-Query notes, we might need (node, null) for FF |
|
4923 getComputedStyle(el) : |
|
4924 |
|
4925 // Otherwise, we are in IE and use currentStyle |
|
4926 el.currentStyle; |
|
4927 if (style) { |
|
4928 return style |
|
4929 [ |
|
4930 // Switch to camelCase for CSSOM |
|
4931 // DEV: Grabbed from jQuery |
|
4932 // https://github.com/jquery/jquery/blob/1.9-stable/src/css.js#L191-L194 |
|
4933 // https://github.com/jquery/jquery/blob/1.9-stable/src/core.js#L593-L597 |
|
4934 prop.replace(/-(\w)/gi, function (word, letter) { |
|
4935 return letter.toUpperCase(); |
|
4936 }) |
|
4937 ]; |
|
4938 } |
|
4939 } |
|
4940 |
|
4941 module.exports = computedStyle; |
|
4942 |
|
4943 },{}],25:[function(_dereq_,module,exports){ |
|
4944 /*! |
|
4945 * https://github.com/es-shims/es5-shim |
|
4946 * @license es5-shim Copyright 2009-2015 by contributors, MIT License |
|
4947 * see https://github.com/es-shims/es5-shim/blob/master/LICENSE |
|
4948 */ |
|
4949 |
|
4950 // vim: ts=4 sts=4 sw=4 expandtab |
|
4951 |
|
4952 // Add semicolon to prevent IIFE from being passed as argument to concatenated code. |
|
4953 ; |
|
4954 |
|
4955 // UMD (Universal Module Definition) |
|
4956 // see https://github.com/umdjs/umd/blob/master/returnExports.js |
|
4957 (function (root, factory) { |
|
4958 'use strict'; |
|
4959 |
|
4960 /* global define, exports, module */ |
|
4961 if (typeof define === 'function' && define.amd) { |
|
4962 // AMD. Register as an anonymous module. |
|
4963 define(factory); |
|
4964 } else if (typeof exports === 'object') { |
|
4965 // Node. Does not work with strict CommonJS, but |
|
4966 // only CommonJS-like enviroments that support module.exports, |
|
4967 // like Node. |
|
4968 module.exports = factory(); |
|
4969 } else { |
|
4970 // Browser globals (root is window) |
|
4971 root.returnExports = factory(); |
|
4972 } |
|
4973 }(this, function () { |
|
4974 |
|
4975 /** |
|
4976 * Brings an environment as close to ECMAScript 5 compliance |
|
4977 * as is possible with the facilities of erstwhile engines. |
|
4978 * |
|
4979 * Annotated ES5: http://es5.github.com/ (specific links below) |
|
4980 * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf |
|
4981 * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/ |
|
4982 */ |
|
4983 |
|
4984 // Shortcut to an often accessed properties, in order to avoid multiple |
|
4985 // dereference that costs universally. This also holds a reference to known-good |
|
4986 // functions. |
|
4987 var $Array = Array; |
|
4988 var ArrayPrototype = $Array.prototype; |
|
4989 var $Object = Object; |
|
4990 var ObjectPrototype = $Object.prototype; |
|
4991 var FunctionPrototype = Function.prototype; |
|
4992 var $String = String; |
|
4993 var StringPrototype = $String.prototype; |
|
4994 var $Number = Number; |
|
4995 var NumberPrototype = $Number.prototype; |
|
4996 var array_slice = ArrayPrototype.slice; |
|
4997 var array_splice = ArrayPrototype.splice; |
|
4998 var array_push = ArrayPrototype.push; |
|
4999 var array_unshift = ArrayPrototype.unshift; |
|
5000 var array_concat = ArrayPrototype.concat; |
|
5001 var call = FunctionPrototype.call; |
|
5002 var max = Math.max; |
|
5003 var min = Math.min; |
|
5004 |
|
5005 // Having a toString local variable name breaks in Opera so use to_string. |
|
5006 var to_string = ObjectPrototype.toString; |
|
5007 |
|
5008 var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'; |
|
5009 var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, tryFunctionObject = function tryFunctionObject(value) { try { fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]'; isCallable = function isCallable(value) { if (typeof value !== 'function') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; }; |
|
5010 var isRegex; /* inlined from https://npmjs.com/is-regex */ var regexExec = RegExp.prototype.exec, tryRegexExec = function tryRegexExec(value) { try { regexExec.call(value); return true; } catch (e) { return false; } }, regexClass = '[object RegExp]'; isRegex = function isRegex(value) { if (typeof value !== 'object') { return false; } return hasToStringTag ? tryRegexExec(value) : to_string.call(value) === regexClass; }; |
|
5011 var isString; /* inlined from https://npmjs.com/is-string */ var strValue = String.prototype.valueOf, tryStringObject = function tryStringObject(value) { try { strValue.call(value); return true; } catch (e) { return false; } }, stringClass = '[object String]'; isString = function isString(value) { if (typeof value === 'string') { return true; } if (typeof value !== 'object') { return false; } return hasToStringTag ? tryStringObject(value) : to_string.call(value) === stringClass; }; |
|
5012 |
|
5013 /* inlined from http://npmjs.com/define-properties */ |
|
5014 var defineProperties = (function (has) { |
|
5015 var supportsDescriptors = $Object.defineProperty && (function () { |
|
5016 try { |
|
5017 var obj = {}; |
|
5018 $Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); |
|
5019 for (var _ in obj) { return false; } |
|
5020 return obj.x === obj; |
|
5021 } catch (e) { /* this is ES3 */ |
|
5022 return false; |
|
5023 } |
|
5024 }()); |
|
5025 |
|
5026 // Define configurable, writable and non-enumerable props |
|
5027 // if they don't exist. |
|
5028 var defineProperty; |
|
5029 if (supportsDescriptors) { |
|
5030 defineProperty = function (object, name, method, forceAssign) { |
|
5031 if (!forceAssign && (name in object)) { return; } |
|
5032 $Object.defineProperty(object, name, { |
|
5033 configurable: true, |
|
5034 enumerable: false, |
|
5035 writable: true, |
|
5036 value: method |
|
5037 }); |
|
5038 }; |
|
5039 } else { |
|
5040 defineProperty = function (object, name, method, forceAssign) { |
|
5041 if (!forceAssign && (name in object)) { return; } |
|
5042 object[name] = method; |
|
5043 }; |
|
5044 } |
|
5045 return function defineProperties(object, map, forceAssign) { |
|
5046 for (var name in map) { |
|
5047 if (has.call(map, name)) { |
|
5048 defineProperty(object, name, map[name], forceAssign); |
|
5049 } |
|
5050 } |
|
5051 }; |
|
5052 }(ObjectPrototype.hasOwnProperty)); |
|
5053 |
|
5054 // |
|
5055 // Util |
|
5056 // ====== |
|
5057 // |
|
5058 |
|
5059 /* replaceable with https://npmjs.com/package/es-abstract /helpers/isPrimitive */ |
|
5060 var isPrimitive = function isPrimitive(input) { |
|
5061 var type = typeof input; |
|
5062 return input === null || (type !== 'object' && type !== 'function'); |
|
5063 }; |
|
5064 |
|
5065 var ES = { |
|
5066 // ES5 9.4 |
|
5067 // http://es5.github.com/#x9.4 |
|
5068 // http://jsperf.com/to-integer |
|
5069 /* replaceable with https://npmjs.com/package/es-abstract ES5.ToInteger */ |
|
5070 ToInteger: function ToInteger(num) { |
|
5071 var n = +num; |
|
5072 if (n !== n) { // isNaN |
|
5073 n = 0; |
|
5074 } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { |
|
5075 n = (n > 0 || -1) * Math.floor(Math.abs(n)); |
|
5076 } |
|
5077 return n; |
|
5078 }, |
|
5079 |
|
5080 /* replaceable with https://npmjs.com/package/es-abstract ES5.ToPrimitive */ |
|
5081 ToPrimitive: function ToPrimitive(input) { |
|
5082 var val, valueOf, toStr; |
|
5083 if (isPrimitive(input)) { |
|
5084 return input; |
|
5085 } |
|
5086 valueOf = input.valueOf; |
|
5087 if (isCallable(valueOf)) { |
|
5088 val = valueOf.call(input); |
|
5089 if (isPrimitive(val)) { |
|
5090 return val; |
|
5091 } |
|
5092 } |
|
5093 toStr = input.toString; |
|
5094 if (isCallable(toStr)) { |
|
5095 val = toStr.call(input); |
|
5096 if (isPrimitive(val)) { |
|
5097 return val; |
|
5098 } |
|
5099 } |
|
5100 throw new TypeError(); |
|
5101 }, |
|
5102 |
|
5103 // ES5 9.9 |
|
5104 // http://es5.github.com/#x9.9 |
|
5105 /* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */ |
|
5106 ToObject: function (o) { |
|
5107 /* jshint eqnull: true */ |
|
5108 if (o == null) { // this matches both null and undefined |
|
5109 throw new TypeError("can't convert " + o + ' to object'); |
|
5110 } |
|
5111 return $Object(o); |
|
5112 }, |
|
5113 |
|
5114 /* replaceable with https://npmjs.com/package/es-abstract ES5.ToUint32 */ |
|
5115 ToUint32: function ToUint32(x) { |
|
5116 return x >>> 0; |
|
5117 } |
|
5118 }; |
|
5119 |
|
5120 // |
|
5121 // Function |
|
5122 // ======== |
|
5123 // |
|
5124 |
|
5125 // ES-5 15.3.4.5 |
|
5126 // http://es5.github.com/#x15.3.4.5 |
|
5127 |
|
5128 var Empty = function Empty() {}; |
|
5129 |
|
5130 defineProperties(FunctionPrototype, { |
|
5131 bind: function bind(that) { // .length is 1 |
|
5132 // 1. Let Target be the this value. |
|
5133 var target = this; |
|
5134 // 2. If IsCallable(Target) is false, throw a TypeError exception. |
|
5135 if (!isCallable(target)) { |
|
5136 throw new TypeError('Function.prototype.bind called on incompatible ' + target); |
|
5137 } |
|
5138 // 3. Let A be a new (possibly empty) internal list of all of the |
|
5139 // argument values provided after thisArg (arg1, arg2 etc), in order. |
|
5140 // XXX slicedArgs will stand in for "A" if used |
|
5141 var args = array_slice.call(arguments, 1); // for normal call |
|
5142 // 4. Let F be a new native ECMAScript object. |
|
5143 // 11. Set the [[Prototype]] internal property of F to the standard |
|
5144 // built-in Function prototype object as specified in 15.3.3.1. |
|
5145 // 12. Set the [[Call]] internal property of F as described in |
|
5146 // 15.3.4.5.1. |
|
5147 // 13. Set the [[Construct]] internal property of F as described in |
|
5148 // 15.3.4.5.2. |
|
5149 // 14. Set the [[HasInstance]] internal property of F as described in |
|
5150 // 15.3.4.5.3. |
|
5151 var bound; |
|
5152 var binder = function () { |
|
5153 |
|
5154 if (this instanceof bound) { |
|
5155 // 15.3.4.5.2 [[Construct]] |
|
5156 // When the [[Construct]] internal method of a function object, |
|
5157 // F that was created using the bind function is called with a |
|
5158 // list of arguments ExtraArgs, the following steps are taken: |
|
5159 // 1. Let target be the value of F's [[TargetFunction]] |
|
5160 // internal property. |
|
5161 // 2. If target has no [[Construct]] internal method, a |
|
5162 // TypeError exception is thrown. |
|
5163 // 3. Let boundArgs be the value of F's [[BoundArgs]] internal |
|
5164 // property. |
|
5165 // 4. Let args be a new list containing the same values as the |
|
5166 // list boundArgs in the same order followed by the same |
|
5167 // values as the list ExtraArgs in the same order. |
|
5168 // 5. Return the result of calling the [[Construct]] internal |
|
5169 // method of target providing args as the arguments. |
|
5170 |
|
5171 var result = target.apply( |
|
5172 this, |
|
5173 array_concat.call(args, array_slice.call(arguments)) |
|
5174 ); |
|
5175 if ($Object(result) === result) { |
|
5176 return result; |
|
5177 } |
|
5178 return this; |
|
5179 |
|
5180 } else { |
|
5181 // 15.3.4.5.1 [[Call]] |
|
5182 // When the [[Call]] internal method of a function object, F, |
|
5183 // which was created using the bind function is called with a |
|
5184 // this value and a list of arguments ExtraArgs, the following |
|
5185 // steps are taken: |
|
5186 // 1. Let boundArgs be the value of F's [[BoundArgs]] internal |
|
5187 // property. |
|
5188 // 2. Let boundThis be the value of F's [[BoundThis]] internal |
|
5189 // property. |
|
5190 // 3. Let target be the value of F's [[TargetFunction]] internal |
|
5191 // property. |
|
5192 // 4. Let args be a new list containing the same values as the |
|
5193 // list boundArgs in the same order followed by the same |
|
5194 // values as the list ExtraArgs in the same order. |
|
5195 // 5. Return the result of calling the [[Call]] internal method |
|
5196 // of target providing boundThis as the this value and |
|
5197 // providing args as the arguments. |
|
5198 |
|
5199 // equiv: target.call(this, ...boundArgs, ...args) |
|
5200 return target.apply( |
|
5201 that, |
|
5202 array_concat.call(args, array_slice.call(arguments)) |
|
5203 ); |
|
5204 |
|
5205 } |
|
5206 |
|
5207 }; |
|
5208 |
|
5209 // 15. If the [[Class]] internal property of Target is "Function", then |
|
5210 // a. Let L be the length property of Target minus the length of A. |
|
5211 // b. Set the length own property of F to either 0 or L, whichever is |
|
5212 // larger. |
|
5213 // 16. Else set the length own property of F to 0. |
|
5214 |
|
5215 var boundLength = max(0, target.length - args.length); |
|
5216 |
|
5217 // 17. Set the attributes of the length own property of F to the values |
|
5218 // specified in 15.3.5.1. |
|
5219 var boundArgs = []; |
|
5220 for (var i = 0; i < boundLength; i++) { |
|
5221 array_push.call(boundArgs, '$' + i); |
|
5222 } |
|
5223 |
|
5224 // XXX Build a dynamic function with desired amount of arguments is the only |
|
5225 // way to set the length property of a function. |
|
5226 // In environments where Content Security Policies enabled (Chrome extensions, |
|
5227 // for ex.) all use of eval or Function costructor throws an exception. |
|
5228 // However in all of these environments Function.prototype.bind exists |
|
5229 // and so this code will never be executed. |
|
5230 bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder); |
|
5231 |
|
5232 if (target.prototype) { |
|
5233 Empty.prototype = target.prototype; |
|
5234 bound.prototype = new Empty(); |
|
5235 // Clean up dangling references. |
|
5236 Empty.prototype = null; |
|
5237 } |
|
5238 |
|
5239 // TODO |
|
5240 // 18. Set the [[Extensible]] internal property of F to true. |
|
5241 |
|
5242 // TODO |
|
5243 // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). |
|
5244 // 20. Call the [[DefineOwnProperty]] internal method of F with |
|
5245 // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: |
|
5246 // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and |
|
5247 // false. |
|
5248 // 21. Call the [[DefineOwnProperty]] internal method of F with |
|
5249 // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, |
|
5250 // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, |
|
5251 // and false. |
|
5252 |
|
5253 // TODO |
|
5254 // NOTE Function objects created using Function.prototype.bind do not |
|
5255 // have a prototype property or the [[Code]], [[FormalParameters]], and |
|
5256 // [[Scope]] internal properties. |
|
5257 // XXX can't delete prototype in pure-js. |
|
5258 |
|
5259 // 22. Return F. |
|
5260 return bound; |
|
5261 } |
|
5262 }); |
|
5263 |
|
5264 // _Please note: Shortcuts are defined after `Function.prototype.bind` as we |
|
5265 // us it in defining shortcuts. |
|
5266 var owns = call.bind(ObjectPrototype.hasOwnProperty); |
|
5267 var toStr = call.bind(ObjectPrototype.toString); |
|
5268 var strSlice = call.bind(StringPrototype.slice); |
|
5269 var strSplit = call.bind(StringPrototype.split); |
|
5270 |
|
5271 // |
|
5272 // Array |
|
5273 // ===== |
|
5274 // |
|
5275 |
|
5276 var isArray = $Array.isArray || function isArray(obj) { |
|
5277 return toStr(obj) === '[object Array]'; |
|
5278 }; |
|
5279 |
|
5280 // ES5 15.4.4.12 |
|
5281 // http://es5.github.com/#x15.4.4.13 |
|
5282 // Return len+argCount. |
|
5283 // [bugfix, ielt8] |
|
5284 // IE < 8 bug: [].unshift(0) === undefined but should be "1" |
|
5285 var hasUnshiftReturnValueBug = [].unshift(0) !== 1; |
|
5286 defineProperties(ArrayPrototype, { |
|
5287 unshift: function () { |
|
5288 array_unshift.apply(this, arguments); |
|
5289 return this.length; |
|
5290 } |
|
5291 }, hasUnshiftReturnValueBug); |
|
5292 |
|
5293 // ES5 15.4.3.2 |
|
5294 // http://es5.github.com/#x15.4.3.2 |
|
5295 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray |
|
5296 defineProperties($Array, { isArray: isArray }); |
|
5297 |
|
5298 // The IsCallable() check in the Array functions |
|
5299 // has been replaced with a strict check on the |
|
5300 // internal class of the object to trap cases where |
|
5301 // the provided function was actually a regular |
|
5302 // expression literal, which in V8 and |
|
5303 // JavaScriptCore is a typeof "function". Only in |
|
5304 // V8 are regular expression literals permitted as |
|
5305 // reduce parameters, so it is desirable in the |
|
5306 // general case for the shim to match the more |
|
5307 // strict and common behavior of rejecting regular |
|
5308 // expressions. |
|
5309 |
|
5310 // ES5 15.4.4.18 |
|
5311 // http://es5.github.com/#x15.4.4.18 |
|
5312 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach |
|
5313 |
|
5314 // Check failure of by-index access of string characters (IE < 9) |
|
5315 // and failure of `0 in boxedString` (Rhino) |
|
5316 var boxedString = $Object('a'); |
|
5317 var splitString = boxedString[0] !== 'a' || !(0 in boxedString); |
|
5318 |
|
5319 var properlyBoxesContext = function properlyBoxed(method) { |
|
5320 // Check node 0.6.21 bug where third parameter is not boxed |
|
5321 var properlyBoxesNonStrict = true; |
|
5322 var properlyBoxesStrict = true; |
|
5323 if (method) { |
|
5324 method.call('foo', function (_, __, context) { |
|
5325 if (typeof context !== 'object') { properlyBoxesNonStrict = false; } |
|
5326 }); |
|
5327 |
|
5328 method.call([1], function () { |
|
5329 'use strict'; |
|
5330 |
|
5331 properlyBoxesStrict = typeof this === 'string'; |
|
5332 }, 'x'); |
|
5333 } |
|
5334 return !!method && properlyBoxesNonStrict && properlyBoxesStrict; |
|
5335 }; |
|
5336 |
|
5337 defineProperties(ArrayPrototype, { |
|
5338 forEach: function forEach(callbackfn /*, thisArg*/) { |
|
5339 var object = ES.ToObject(this); |
|
5340 var self = splitString && isString(this) ? strSplit(this, '') : object; |
|
5341 var i = -1; |
|
5342 var length = self.length >>> 0; |
|
5343 var T; |
|
5344 if (arguments.length > 1) { |
|
5345 T = arguments[1]; |
|
5346 } |
|
5347 |
|
5348 // If no callback function or if callback is not a callable function |
|
5349 if (!isCallable(callbackfn)) { |
|
5350 throw new TypeError('Array.prototype.forEach callback must be a function'); |
|
5351 } |
|
5352 |
|
5353 while (++i < length) { |
|
5354 if (i in self) { |
|
5355 // Invoke the callback function with call, passing arguments: |
|
5356 // context, property value, property key, thisArg object |
|
5357 if (typeof T !== 'undefined') { |
|
5358 callbackfn.call(T, self[i], i, object); |
|
5359 } else { |
|
5360 callbackfn(self[i], i, object); |
|
5361 } |
|
5362 } |
|
5363 } |
|
5364 } |
|
5365 }, !properlyBoxesContext(ArrayPrototype.forEach)); |
|
5366 |
|
5367 // ES5 15.4.4.19 |
|
5368 // http://es5.github.com/#x15.4.4.19 |
|
5369 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map |
|
5370 defineProperties(ArrayPrototype, { |
|
5371 map: function map(callbackfn/*, thisArg*/) { |
|
5372 var object = ES.ToObject(this); |
|
5373 var self = splitString && isString(this) ? strSplit(this, '') : object; |
|
5374 var length = self.length >>> 0; |
|
5375 var result = $Array(length); |
|
5376 var T; |
|
5377 if (arguments.length > 1) { |
|
5378 T = arguments[1]; |
|
5379 } |
|
5380 |
|
5381 // If no callback function or if callback is not a callable function |
|
5382 if (!isCallable(callbackfn)) { |
|
5383 throw new TypeError('Array.prototype.map callback must be a function'); |
|
5384 } |
|
5385 |
|
5386 for (var i = 0; i < length; i++) { |
|
5387 if (i in self) { |
|
5388 if (typeof T !== 'undefined') { |
|
5389 result[i] = callbackfn.call(T, self[i], i, object); |
|
5390 } else { |
|
5391 result[i] = callbackfn(self[i], i, object); |
|
5392 } |
|
5393 } |
|
5394 } |
|
5395 return result; |
|
5396 } |
|
5397 }, !properlyBoxesContext(ArrayPrototype.map)); |
|
5398 |
|
5399 // ES5 15.4.4.20 |
|
5400 // http://es5.github.com/#x15.4.4.20 |
|
5401 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter |
|
5402 defineProperties(ArrayPrototype, { |
|
5403 filter: function filter(callbackfn /*, thisArg*/) { |
|
5404 var object = ES.ToObject(this); |
|
5405 var self = splitString && isString(this) ? strSplit(this, '') : object; |
|
5406 var length = self.length >>> 0; |
|
5407 var result = []; |
|
5408 var value; |
|
5409 var T; |
|
5410 if (arguments.length > 1) { |
|
5411 T = arguments[1]; |
|
5412 } |
|
5413 |
|
5414 // If no callback function or if callback is not a callable function |
|
5415 if (!isCallable(callbackfn)) { |
|
5416 throw new TypeError('Array.prototype.filter callback must be a function'); |
|
5417 } |
|
5418 |
|
5419 for (var i = 0; i < length; i++) { |
|
5420 if (i in self) { |
|
5421 value = self[i]; |
|
5422 if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) { |
|
5423 array_push.call(result, value); |
|
5424 } |
|
5425 } |
|
5426 } |
|
5427 return result; |
|
5428 } |
|
5429 }, !properlyBoxesContext(ArrayPrototype.filter)); |
|
5430 |
|
5431 // ES5 15.4.4.16 |
|
5432 // http://es5.github.com/#x15.4.4.16 |
|
5433 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every |
|
5434 defineProperties(ArrayPrototype, { |
|
5435 every: function every(callbackfn /*, thisArg*/) { |
|
5436 var object = ES.ToObject(this); |
|
5437 var self = splitString && isString(this) ? strSplit(this, '') : object; |
|
5438 var length = self.length >>> 0; |
|
5439 var T; |
|
5440 if (arguments.length > 1) { |
|
5441 T = arguments[1]; |
|
5442 } |
|
5443 |
|
5444 // If no callback function or if callback is not a callable function |
|
5445 if (!isCallable(callbackfn)) { |
|
5446 throw new TypeError('Array.prototype.every callback must be a function'); |
|
5447 } |
|
5448 |
|
5449 for (var i = 0; i < length; i++) { |
|
5450 if (i in self && !(typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { |
|
5451 return false; |
|
5452 } |
|
5453 } |
|
5454 return true; |
|
5455 } |
|
5456 }, !properlyBoxesContext(ArrayPrototype.every)); |
|
5457 |
|
5458 // ES5 15.4.4.17 |
|
5459 // http://es5.github.com/#x15.4.4.17 |
|
5460 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some |
|
5461 defineProperties(ArrayPrototype, { |
|
5462 some: function some(callbackfn/*, thisArg */) { |
|
5463 var object = ES.ToObject(this); |
|
5464 var self = splitString && isString(this) ? strSplit(this, '') : object; |
|
5465 var length = self.length >>> 0; |
|
5466 var T; |
|
5467 if (arguments.length > 1) { |
|
5468 T = arguments[1]; |
|
5469 } |
|
5470 |
|
5471 // If no callback function or if callback is not a callable function |
|
5472 if (!isCallable(callbackfn)) { |
|
5473 throw new TypeError('Array.prototype.some callback must be a function'); |
|
5474 } |
|
5475 |
|
5476 for (var i = 0; i < length; i++) { |
|
5477 if (i in self && (typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { |
|
5478 return true; |
|
5479 } |
|
5480 } |
|
5481 return false; |
|
5482 } |
|
5483 }, !properlyBoxesContext(ArrayPrototype.some)); |
|
5484 |
|
5485 // ES5 15.4.4.21 |
|
5486 // http://es5.github.com/#x15.4.4.21 |
|
5487 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce |
|
5488 var reduceCoercesToObject = false; |
|
5489 if (ArrayPrototype.reduce) { |
|
5490 reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object'; |
|
5491 } |
|
5492 defineProperties(ArrayPrototype, { |
|
5493 reduce: function reduce(callbackfn /*, initialValue*/) { |
|
5494 var object = ES.ToObject(this); |
|
5495 var self = splitString && isString(this) ? strSplit(this, '') : object; |
|
5496 var length = self.length >>> 0; |
|
5497 |
|
5498 // If no callback function or if callback is not a callable function |
|
5499 if (!isCallable(callbackfn)) { |
|
5500 throw new TypeError('Array.prototype.reduce callback must be a function'); |
|
5501 } |
|
5502 |
|
5503 // no value to return if no initial value and an empty array |
|
5504 if (length === 0 && arguments.length === 1) { |
|
5505 throw new TypeError('reduce of empty array with no initial value'); |
|
5506 } |
|
5507 |
|
5508 var i = 0; |
|
5509 var result; |
|
5510 if (arguments.length >= 2) { |
|
5511 result = arguments[1]; |
|
5512 } else { |
|
5513 do { |
|
5514 if (i in self) { |
|
5515 result = self[i++]; |
|
5516 break; |
|
5517 } |
|
5518 |
|
5519 // if array contains no values, no initial value to return |
|
5520 if (++i >= length) { |
|
5521 throw new TypeError('reduce of empty array with no initial value'); |
|
5522 } |
|
5523 } while (true); |
|
5524 } |
|
5525 |
|
5526 for (; i < length; i++) { |
|
5527 if (i in self) { |
|
5528 result = callbackfn(result, self[i], i, object); |
|
5529 } |
|
5530 } |
|
5531 |
|
5532 return result; |
|
5533 } |
|
5534 }, !reduceCoercesToObject); |
|
5535 |
|
5536 // ES5 15.4.4.22 |
|
5537 // http://es5.github.com/#x15.4.4.22 |
|
5538 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight |
|
5539 var reduceRightCoercesToObject = false; |
|
5540 if (ArrayPrototype.reduceRight) { |
|
5541 reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object'; |
|
5542 } |
|
5543 defineProperties(ArrayPrototype, { |
|
5544 reduceRight: function reduceRight(callbackfn/*, initial*/) { |
|
5545 var object = ES.ToObject(this); |
|
5546 var self = splitString && isString(this) ? strSplit(this, '') : object; |
|
5547 var length = self.length >>> 0; |
|
5548 |
|
5549 // If no callback function or if callback is not a callable function |
|
5550 if (!isCallable(callbackfn)) { |
|
5551 throw new TypeError('Array.prototype.reduceRight callback must be a function'); |
|
5552 } |
|
5553 |
|
5554 // no value to return if no initial value, empty array |
|
5555 if (length === 0 && arguments.length === 1) { |
|
5556 throw new TypeError('reduceRight of empty array with no initial value'); |
|
5557 } |
|
5558 |
|
5559 var result; |
|
5560 var i = length - 1; |
|
5561 if (arguments.length >= 2) { |
|
5562 result = arguments[1]; |
|
5563 } else { |
|
5564 do { |
|
5565 if (i in self) { |
|
5566 result = self[i--]; |
|
5567 break; |
|
5568 } |
|
5569 |
|
5570 // if array contains no values, no initial value to return |
|
5571 if (--i < 0) { |
|
5572 throw new TypeError('reduceRight of empty array with no initial value'); |
|
5573 } |
|
5574 } while (true); |
|
5575 } |
|
5576 |
|
5577 if (i < 0) { |
|
5578 return result; |
|
5579 } |
|
5580 |
|
5581 do { |
|
5582 if (i in self) { |
|
5583 result = callbackfn(result, self[i], i, object); |
|
5584 } |
|
5585 } while (i--); |
|
5586 |
|
5587 return result; |
|
5588 } |
|
5589 }, !reduceRightCoercesToObject); |
|
5590 |
|
5591 // ES5 15.4.4.14 |
|
5592 // http://es5.github.com/#x15.4.4.14 |
|
5593 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf |
|
5594 var hasFirefox2IndexOfBug = ArrayPrototype.indexOf && [0, 1].indexOf(1, 2) !== -1; |
|
5595 defineProperties(ArrayPrototype, { |
|
5596 indexOf: function indexOf(searchElement /*, fromIndex */) { |
|
5597 var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); |
|
5598 var length = self.length >>> 0; |
|
5599 |
|
5600 if (length === 0) { |
|
5601 return -1; |
|
5602 } |
|
5603 |
|
5604 var i = 0; |
|
5605 if (arguments.length > 1) { |
|
5606 i = ES.ToInteger(arguments[1]); |
|
5607 } |
|
5608 |
|
5609 // handle negative indices |
|
5610 i = i >= 0 ? i : max(0, length + i); |
|
5611 for (; i < length; i++) { |
|
5612 if (i in self && self[i] === searchElement) { |
|
5613 return i; |
|
5614 } |
|
5615 } |
|
5616 return -1; |
|
5617 } |
|
5618 }, hasFirefox2IndexOfBug); |
|
5619 |
|
5620 // ES5 15.4.4.15 |
|
5621 // http://es5.github.com/#x15.4.4.15 |
|
5622 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf |
|
5623 var hasFirefox2LastIndexOfBug = ArrayPrototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1; |
|
5624 defineProperties(ArrayPrototype, { |
|
5625 lastIndexOf: function lastIndexOf(searchElement /*, fromIndex */) { |
|
5626 var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); |
|
5627 var length = self.length >>> 0; |
|
5628 |
|
5629 if (length === 0) { |
|
5630 return -1; |
|
5631 } |
|
5632 var i = length - 1; |
|
5633 if (arguments.length > 1) { |
|
5634 i = min(i, ES.ToInteger(arguments[1])); |
|
5635 } |
|
5636 // handle negative indices |
|
5637 i = i >= 0 ? i : length - Math.abs(i); |
|
5638 for (; i >= 0; i--) { |
|
5639 if (i in self && searchElement === self[i]) { |
|
5640 return i; |
|
5641 } |
|
5642 } |
|
5643 return -1; |
|
5644 } |
|
5645 }, hasFirefox2LastIndexOfBug); |
|
5646 |
|
5647 // ES5 15.4.4.12 |
|
5648 // http://es5.github.com/#x15.4.4.12 |
|
5649 var spliceNoopReturnsEmptyArray = (function () { |
|
5650 var a = [1, 2]; |
|
5651 var result = a.splice(); |
|
5652 return a.length === 2 && isArray(result) && result.length === 0; |
|
5653 }()); |
|
5654 defineProperties(ArrayPrototype, { |
|
5655 // Safari 5.0 bug where .splice() returns undefined |
|
5656 splice: function splice(start, deleteCount) { |
|
5657 if (arguments.length === 0) { |
|
5658 return []; |
|
5659 } else { |
|
5660 return array_splice.apply(this, arguments); |
|
5661 } |
|
5662 } |
|
5663 }, !spliceNoopReturnsEmptyArray); |
|
5664 |
|
5665 var spliceWorksWithEmptyObject = (function () { |
|
5666 var obj = {}; |
|
5667 ArrayPrototype.splice.call(obj, 0, 0, 1); |
|
5668 return obj.length === 1; |
|
5669 }()); |
|
5670 defineProperties(ArrayPrototype, { |
|
5671 splice: function splice(start, deleteCount) { |
|
5672 if (arguments.length === 0) { return []; } |
|
5673 var args = arguments; |
|
5674 this.length = max(ES.ToInteger(this.length), 0); |
|
5675 if (arguments.length > 0 && typeof deleteCount !== 'number') { |
|
5676 args = array_slice.call(arguments); |
|
5677 if (args.length < 2) { |
|
5678 array_push.call(args, this.length - start); |
|
5679 } else { |
|
5680 args[1] = ES.ToInteger(deleteCount); |
|
5681 } |
|
5682 } |
|
5683 return array_splice.apply(this, args); |
|
5684 } |
|
5685 }, !spliceWorksWithEmptyObject); |
|
5686 var spliceWorksWithLargeSparseArrays = (function () { |
|
5687 // Per https://github.com/es-shims/es5-shim/issues/295 |
|
5688 // Safari 7/8 breaks with sparse arrays of size 1e5 or greater |
|
5689 var arr = new $Array(1e5); |
|
5690 // note: the index MUST be 8 or larger or the test will false pass |
|
5691 arr[8] = 'x'; |
|
5692 arr.splice(1, 1); |
|
5693 // note: this test must be defined *after* the indexOf shim |
|
5694 // per https://github.com/es-shims/es5-shim/issues/313 |
|
5695 return arr.indexOf('x') === 7; |
|
5696 }()); |
|
5697 var spliceWorksWithSmallSparseArrays = (function () { |
|
5698 // Per https://github.com/es-shims/es5-shim/issues/295 |
|
5699 // Opera 12.15 breaks on this, no idea why. |
|
5700 var n = 256; |
|
5701 var arr = []; |
|
5702 arr[n] = 'a'; |
|
5703 arr.splice(n + 1, 0, 'b'); |
|
5704 return arr[n] === 'a'; |
|
5705 }()); |
|
5706 defineProperties(ArrayPrototype, { |
|
5707 splice: function splice(start, deleteCount) { |
|
5708 var O = ES.ToObject(this); |
|
5709 var A = []; |
|
5710 var len = ES.ToUint32(O.length); |
|
5711 var relativeStart = ES.ToInteger(start); |
|
5712 var actualStart = relativeStart < 0 ? max((len + relativeStart), 0) : min(relativeStart, len); |
|
5713 var actualDeleteCount = min(max(ES.ToInteger(deleteCount), 0), len - actualStart); |
|
5714 |
|
5715 var k = 0; |
|
5716 var from; |
|
5717 while (k < actualDeleteCount) { |
|
5718 from = $String(actualStart + k); |
|
5719 if (owns(O, from)) { |
|
5720 A[k] = O[from]; |
|
5721 } |
|
5722 k += 1; |
|
5723 } |
|
5724 |
|
5725 var items = array_slice.call(arguments, 2); |
|
5726 var itemCount = items.length; |
|
5727 var to; |
|
5728 if (itemCount < actualDeleteCount) { |
|
5729 k = actualStart; |
|
5730 while (k < (len - actualDeleteCount)) { |
|
5731 from = $String(k + actualDeleteCount); |
|
5732 to = $String(k + itemCount); |
|
5733 if (owns(O, from)) { |
|
5734 O[to] = O[from]; |
|
5735 } else { |
|
5736 delete O[to]; |
|
5737 } |
|
5738 k += 1; |
|
5739 } |
|
5740 k = len; |
|
5741 while (k > (len - actualDeleteCount + itemCount)) { |
|
5742 delete O[k - 1]; |
|
5743 k -= 1; |
|
5744 } |
|
5745 } else if (itemCount > actualDeleteCount) { |
|
5746 k = len - actualDeleteCount; |
|
5747 while (k > actualStart) { |
|
5748 from = $String(k + actualDeleteCount - 1); |
|
5749 to = $String(k + itemCount - 1); |
|
5750 if (owns(O, from)) { |
|
5751 O[to] = O[from]; |
|
5752 } else { |
|
5753 delete O[to]; |
|
5754 } |
|
5755 k -= 1; |
|
5756 } |
|
5757 } |
|
5758 k = actualStart; |
|
5759 for (var i = 0; i < items.length; ++i) { |
|
5760 O[k] = items[i]; |
|
5761 k += 1; |
|
5762 } |
|
5763 O.length = len - actualDeleteCount + itemCount; |
|
5764 |
|
5765 return A; |
|
5766 } |
|
5767 }, !spliceWorksWithLargeSparseArrays || !spliceWorksWithSmallSparseArrays); |
|
5768 |
|
5769 // |
|
5770 // Object |
|
5771 // ====== |
|
5772 // |
|
5773 |
|
5774 // ES5 15.2.3.14 |
|
5775 // http://es5.github.com/#x15.2.3.14 |
|
5776 |
|
5777 // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation |
|
5778 var hasDontEnumBug = !({ 'toString': null }).propertyIsEnumerable('toString'); |
|
5779 var hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'); |
|
5780 var hasStringEnumBug = !owns('x', '0'); |
|
5781 var equalsConstructorPrototype = function (o) { |
|
5782 var ctor = o.constructor; |
|
5783 return ctor && ctor.prototype === o; |
|
5784 }; |
|
5785 var blacklistedKeys = { |
|
5786 $window: true, |
|
5787 $console: true, |
|
5788 $parent: true, |
|
5789 $self: true, |
|
5790 $frames: true, |
|
5791 $frameElement: true, |
|
5792 $webkitIndexedDB: true, |
|
5793 $webkitStorageInfo: true |
|
5794 }; |
|
5795 var hasAutomationEqualityBug = (function () { |
|
5796 /* globals window */ |
|
5797 if (typeof window === 'undefined') { return false; } |
|
5798 for (var k in window) { |
|
5799 if (!blacklistedKeys['$' + k] && owns(window, k) && window[k] !== null && typeof window[k] === 'object') { |
|
5800 try { |
|
5801 equalsConstructorPrototype(window[k]); |
|
5802 } catch (e) { |
|
5803 return true; |
|
5804 } |
|
5805 } |
|
5806 } |
|
5807 return false; |
|
5808 }()); |
|
5809 var equalsConstructorPrototypeIfNotBuggy = function (object) { |
|
5810 if (typeof window === 'undefined' || !hasAutomationEqualityBug) { return equalsConstructorPrototype(object); } |
|
5811 try { |
|
5812 return equalsConstructorPrototype(object); |
|
5813 } catch (e) { |
|
5814 return false; |
|
5815 } |
|
5816 }; |
|
5817 var dontEnums = [ |
|
5818 'toString', |
|
5819 'toLocaleString', |
|
5820 'valueOf', |
|
5821 'hasOwnProperty', |
|
5822 'isPrototypeOf', |
|
5823 'propertyIsEnumerable', |
|
5824 'constructor' |
|
5825 ]; |
|
5826 var dontEnumsLength = dontEnums.length; |
|
5827 |
|
5828 var isArguments = function isArguments(value) { |
|
5829 var str = toStr(value); |
|
5830 var isArgs = str === '[object Arguments]'; |
|
5831 if (!isArgs) { |
|
5832 isArgs = !isArray(value) && |
|
5833 value !== null && |
|
5834 typeof value === 'object' && |
|
5835 typeof value.length === 'number' && |
|
5836 value.length >= 0 && |
|
5837 isCallable(value.callee); |
|
5838 } |
|
5839 return isArgs; |
|
5840 }; |
|
5841 |
|
5842 defineProperties($Object, { |
|
5843 keys: function keys(object) { |
|
5844 var isFn = isCallable(object); |
|
5845 var isArgs = isArguments(object); |
|
5846 var isObject = object !== null && typeof object === 'object'; |
|
5847 var isStr = isObject && isString(object); |
|
5848 |
|
5849 if (!isObject && !isFn && !isArgs) { |
|
5850 throw new TypeError('Object.keys called on a non-object'); |
|
5851 } |
|
5852 |
|
5853 var theKeys = []; |
|
5854 var skipProto = hasProtoEnumBug && isFn; |
|
5855 if ((isStr && hasStringEnumBug) || isArgs) { |
|
5856 for (var i = 0; i < object.length; ++i) { |
|
5857 array_push.call(theKeys, $String(i)); |
|
5858 } |
|
5859 } |
|
5860 |
|
5861 if (!isArgs) { |
|
5862 for (var name in object) { |
|
5863 if (!(skipProto && name === 'prototype') && owns(object, name)) { |
|
5864 array_push.call(theKeys, $String(name)); |
|
5865 } |
|
5866 } |
|
5867 } |
|
5868 |
|
5869 if (hasDontEnumBug) { |
|
5870 var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); |
|
5871 for (var j = 0; j < dontEnumsLength; j++) { |
|
5872 var dontEnum = dontEnums[j]; |
|
5873 if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) { |
|
5874 array_push.call(theKeys, dontEnum); |
|
5875 } |
|
5876 } |
|
5877 } |
|
5878 return theKeys; |
|
5879 } |
|
5880 }); |
|
5881 |
|
5882 var keysWorksWithArguments = $Object.keys && (function () { |
|
5883 // Safari 5.0 bug |
|
5884 return $Object.keys(arguments).length === 2; |
|
5885 }(1, 2)); |
|
5886 var originalKeys = $Object.keys; |
|
5887 defineProperties($Object, { |
|
5888 keys: function keys(object) { |
|
5889 if (isArguments(object)) { |
|
5890 return originalKeys(array_slice.call(object)); |
|
5891 } else { |
|
5892 return originalKeys(object); |
|
5893 } |
|
5894 } |
|
5895 }, !keysWorksWithArguments); |
|
5896 |
|
5897 // |
|
5898 // Date |
|
5899 // ==== |
|
5900 // |
|
5901 |
|
5902 // ES5 15.9.5.43 |
|
5903 // http://es5.github.com/#x15.9.5.43 |
|
5904 // This function returns a String value represent the instance in time |
|
5905 // represented by this Date object. The format of the String is the Date Time |
|
5906 // string format defined in 15.9.1.15. All fields are present in the String. |
|
5907 // The time zone is always UTC, denoted by the suffix Z. If the time value of |
|
5908 // this object is not a finite Number a RangeError exception is thrown. |
|
5909 var negativeDate = -62198755200000; |
|
5910 var negativeYearString = '-000001'; |
|
5911 var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1; |
|
5912 var hasSafari51DateBug = Date.prototype.toISOString && new Date(-1).toISOString() !== '1969-12-31T23:59:59.999Z'; |
|
5913 |
|
5914 defineProperties(Date.prototype, { |
|
5915 toISOString: function toISOString() { |
|
5916 var result, length, value, year, month; |
|
5917 if (!isFinite(this)) { |
|
5918 throw new RangeError('Date.prototype.toISOString called on non-finite value.'); |
|
5919 } |
|
5920 |
|
5921 year = this.getUTCFullYear(); |
|
5922 |
|
5923 month = this.getUTCMonth(); |
|
5924 // see https://github.com/es-shims/es5-shim/issues/111 |
|
5925 year += Math.floor(month / 12); |
|
5926 month = (month % 12 + 12) % 12; |
|
5927 |
|
5928 // the date time string format is specified in 15.9.1.15. |
|
5929 result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()]; |
|
5930 year = ( |
|
5931 (year < 0 ? '-' : (year > 9999 ? '+' : '')) + |
|
5932 strSlice('00000' + Math.abs(year), (0 <= year && year <= 9999) ? -4 : -6) |
|
5933 ); |
|
5934 |
|
5935 length = result.length; |
|
5936 while (length--) { |
|
5937 value = result[length]; |
|
5938 // pad months, days, hours, minutes, and seconds to have two |
|
5939 // digits. |
|
5940 if (value < 10) { |
|
5941 result[length] = '0' + value; |
|
5942 } |
|
5943 } |
|
5944 // pad milliseconds to have three digits. |
|
5945 return ( |
|
5946 year + '-' + array_slice.call(result, 0, 2).join('-') + |
|
5947 'T' + array_slice.call(result, 2).join(':') + '.' + |
|
5948 strSlice('000' + this.getUTCMilliseconds(), -3) + 'Z' |
|
5949 ); |
|
5950 } |
|
5951 }, hasNegativeDateBug || hasSafari51DateBug); |
|
5952 |
|
5953 // ES5 15.9.5.44 |
|
5954 // http://es5.github.com/#x15.9.5.44 |
|
5955 // This function provides a String representation of a Date object for use by |
|
5956 // JSON.stringify (15.12.3). |
|
5957 var dateToJSONIsSupported = (function () { |
|
5958 try { |
|
5959 return Date.prototype.toJSON && |
|
5960 new Date(NaN).toJSON() === null && |
|
5961 new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 && |
|
5962 Date.prototype.toJSON.call({ // generic |
|
5963 toISOString: function () { return true; } |
|
5964 }); |
|
5965 } catch (e) { |
|
5966 return false; |
|
5967 } |
|
5968 }()); |
|
5969 if (!dateToJSONIsSupported) { |
|
5970 Date.prototype.toJSON = function toJSON(key) { |
|
5971 // When the toJSON method is called with argument key, the following |
|
5972 // steps are taken: |
|
5973 |
|
5974 // 1. Let O be the result of calling ToObject, giving it the this |
|
5975 // value as its argument. |
|
5976 // 2. Let tv be ES.ToPrimitive(O, hint Number). |
|
5977 var O = $Object(this); |
|
5978 var tv = ES.ToPrimitive(O); |
|
5979 // 3. If tv is a Number and is not finite, return null. |
|
5980 if (typeof tv === 'number' && !isFinite(tv)) { |
|
5981 return null; |
|
5982 } |
|
5983 // 4. Let toISO be the result of calling the [[Get]] internal method of |
|
5984 // O with argument "toISOString". |
|
5985 var toISO = O.toISOString; |
|
5986 // 5. If IsCallable(toISO) is false, throw a TypeError exception. |
|
5987 if (!isCallable(toISO)) { |
|
5988 throw new TypeError('toISOString property is not callable'); |
|
5989 } |
|
5990 // 6. Return the result of calling the [[Call]] internal method of |
|
5991 // toISO with O as the this value and an empty argument list. |
|
5992 return toISO.call(O); |
|
5993 |
|
5994 // NOTE 1 The argument is ignored. |
|
5995 |
|
5996 // NOTE 2 The toJSON function is intentionally generic; it does not |
|
5997 // require that its this value be a Date object. Therefore, it can be |
|
5998 // transferred to other kinds of objects for use as a method. However, |
|
5999 // it does require that any such object have a toISOString method. An |
|
6000 // object is free to use the argument key to filter its |
|
6001 // stringification. |
|
6002 }; |
|
6003 } |
|
6004 |
|
6005 // ES5 15.9.4.2 |
|
6006 // http://es5.github.com/#x15.9.4.2 |
|
6007 // based on work shared by Daniel Friesen (dantman) |
|
6008 // http://gist.github.com/303249 |
|
6009 var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15; |
|
6010 var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')) || !isNaN(Date.parse('2012-12-31T23:59:60.000Z')); |
|
6011 var doesNotParseY2KNewYear = isNaN(Date.parse('2000-01-01T00:00:00.000Z')); |
|
6012 if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) { |
|
6013 // XXX global assignment won't work in embeddings that use |
|
6014 // an alternate object for the context. |
|
6015 /* global Date: true */ |
|
6016 /* eslint-disable no-undef */ |
|
6017 Date = (function (NativeDate) { |
|
6018 /* eslint-enable no-undef */ |
|
6019 // Date.length === 7 |
|
6020 var DateShim = function Date(Y, M, D, h, m, s, ms) { |
|
6021 var length = arguments.length; |
|
6022 var date; |
|
6023 if (this instanceof NativeDate) { |
|
6024 date = length === 1 && $String(Y) === Y ? // isString(Y) |
|
6025 // We explicitly pass it through parse: |
|
6026 new NativeDate(DateShim.parse(Y)) : |
|
6027 // We have to manually make calls depending on argument |
|
6028 // length here |
|
6029 length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) : |
|
6030 length >= 6 ? new NativeDate(Y, M, D, h, m, s) : |
|
6031 length >= 5 ? new NativeDate(Y, M, D, h, m) : |
|
6032 length >= 4 ? new NativeDate(Y, M, D, h) : |
|
6033 length >= 3 ? new NativeDate(Y, M, D) : |
|
6034 length >= 2 ? new NativeDate(Y, M) : |
|
6035 length >= 1 ? new NativeDate(Y) : |
|
6036 new NativeDate(); |
|
6037 } else { |
|
6038 date = NativeDate.apply(this, arguments); |
|
6039 } |
|
6040 // Prevent mixups with unfixed Date object |
|
6041 defineProperties(date, { constructor: DateShim }, true); |
|
6042 return date; |
|
6043 }; |
|
6044 |
|
6045 // 15.9.1.15 Date Time String Format. |
|
6046 var isoDateExpression = new RegExp('^' + |
|
6047 '(\\d{4}|[+-]\\d{6})' + // four-digit year capture or sign + |
|
6048 // 6-digit extended year |
|
6049 '(?:-(\\d{2})' + // optional month capture |
|
6050 '(?:-(\\d{2})' + // optional day capture |
|
6051 '(?:' + // capture hours:minutes:seconds.milliseconds |
|
6052 'T(\\d{2})' + // hours capture |
|
6053 ':(\\d{2})' + // minutes capture |
|
6054 '(?:' + // optional :seconds.milliseconds |
|
6055 ':(\\d{2})' + // seconds capture |
|
6056 '(?:(\\.\\d{1,}))?' + // milliseconds capture |
|
6057 ')?' + |
|
6058 '(' + // capture UTC offset component |
|
6059 'Z|' + // UTC capture |
|
6060 '(?:' + // offset specifier +/-hours:minutes |
|
6061 '([-+])' + // sign capture |
|
6062 '(\\d{2})' + // hours offset capture |
|
6063 ':(\\d{2})' + // minutes offset capture |
|
6064 ')' + |
|
6065 ')?)?)?)?' + |
|
6066 '$'); |
|
6067 |
|
6068 var months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; |
|
6069 |
|
6070 var dayFromMonth = function dayFromMonth(year, month) { |
|
6071 var t = month > 1 ? 1 : 0; |
|
6072 return ( |
|
6073 months[month] + |
|
6074 Math.floor((year - 1969 + t) / 4) - |
|
6075 Math.floor((year - 1901 + t) / 100) + |
|
6076 Math.floor((year - 1601 + t) / 400) + |
|
6077 365 * (year - 1970) |
|
6078 ); |
|
6079 }; |
|
6080 |
|
6081 var toUTC = function toUTC(t) { |
|
6082 return $Number(new NativeDate(1970, 0, 1, 0, 0, 0, t)); |
|
6083 }; |
|
6084 |
|
6085 // Copy any custom methods a 3rd party library may have added |
|
6086 for (var key in NativeDate) { |
|
6087 if (owns(NativeDate, key)) { |
|
6088 DateShim[key] = NativeDate[key]; |
|
6089 } |
|
6090 } |
|
6091 |
|
6092 // Copy "native" methods explicitly; they may be non-enumerable |
|
6093 defineProperties(DateShim, { |
|
6094 now: NativeDate.now, |
|
6095 UTC: NativeDate.UTC |
|
6096 }, true); |
|
6097 DateShim.prototype = NativeDate.prototype; |
|
6098 defineProperties(DateShim.prototype, { |
|
6099 constructor: DateShim |
|
6100 }, true); |
|
6101 |
|
6102 // Upgrade Date.parse to handle simplified ISO 8601 strings |
|
6103 var parseShim = function parse(string) { |
|
6104 var match = isoDateExpression.exec(string); |
|
6105 if (match) { |
|
6106 // parse months, days, hours, minutes, seconds, and milliseconds |
|
6107 // provide default values if necessary |
|
6108 // parse the UTC offset component |
|
6109 var year = $Number(match[1]), |
|
6110 month = $Number(match[2] || 1) - 1, |
|
6111 day = $Number(match[3] || 1) - 1, |
|
6112 hour = $Number(match[4] || 0), |
|
6113 minute = $Number(match[5] || 0), |
|
6114 second = $Number(match[6] || 0), |
|
6115 millisecond = Math.floor($Number(match[7] || 0) * 1000), |
|
6116 // When time zone is missed, local offset should be used |
|
6117 // (ES 5.1 bug) |
|
6118 // see https://bugs.ecmascript.org/show_bug.cgi?id=112 |
|
6119 isLocalTime = Boolean(match[4] && !match[8]), |
|
6120 signOffset = match[9] === '-' ? 1 : -1, |
|
6121 hourOffset = $Number(match[10] || 0), |
|
6122 minuteOffset = $Number(match[11] || 0), |
|
6123 result; |
|
6124 if ( |
|
6125 hour < ( |
|
6126 minute > 0 || second > 0 || millisecond > 0 ? |
|
6127 24 : 25 |
|
6128 ) && |
|
6129 minute < 60 && second < 60 && millisecond < 1000 && |
|
6130 month > -1 && month < 12 && hourOffset < 24 && |
|
6131 minuteOffset < 60 && // detect invalid offsets |
|
6132 day > -1 && |
|
6133 day < ( |
|
6134 dayFromMonth(year, month + 1) - |
|
6135 dayFromMonth(year, month) |
|
6136 ) |
|
6137 ) { |
|
6138 result = ( |
|
6139 (dayFromMonth(year, month) + day) * 24 + |
|
6140 hour + |
|
6141 hourOffset * signOffset |
|
6142 ) * 60; |
|
6143 result = ( |
|
6144 (result + minute + minuteOffset * signOffset) * 60 + |
|
6145 second |
|
6146 ) * 1000 + millisecond; |
|
6147 if (isLocalTime) { |
|
6148 result = toUTC(result); |
|
6149 } |
|
6150 if (-8.64e15 <= result && result <= 8.64e15) { |
|
6151 return result; |
|
6152 } |
|
6153 } |
|
6154 return NaN; |
|
6155 } |
|
6156 return NativeDate.parse.apply(this, arguments); |
|
6157 }; |
|
6158 defineProperties(DateShim, { parse: parseShim }); |
|
6159 |
|
6160 return DateShim; |
|
6161 }(Date)); |
|
6162 /* global Date: false */ |
|
6163 } |
|
6164 |
|
6165 // ES5 15.9.4.4 |
|
6166 // http://es5.github.com/#x15.9.4.4 |
|
6167 if (!Date.now) { |
|
6168 Date.now = function now() { |
|
6169 return new Date().getTime(); |
|
6170 }; |
|
6171 } |
|
6172 |
|
6173 // |
|
6174 // Number |
|
6175 // ====== |
|
6176 // |
|
6177 |
|
6178 // ES5.1 15.7.4.5 |
|
6179 // http://es5.github.com/#x15.7.4.5 |
|
6180 var hasToFixedBugs = NumberPrototype.toFixed && ( |
|
6181 (0.00008).toFixed(3) !== '0.000' || |
|
6182 (0.9).toFixed(0) !== '1' || |
|
6183 (1.255).toFixed(2) !== '1.25' || |
|
6184 (1000000000000000128).toFixed(0) !== '1000000000000000128' |
|
6185 ); |
|
6186 |
|
6187 var toFixedHelpers = { |
|
6188 base: 1e7, |
|
6189 size: 6, |
|
6190 data: [0, 0, 0, 0, 0, 0], |
|
6191 multiply: function multiply(n, c) { |
|
6192 var i = -1; |
|
6193 var c2 = c; |
|
6194 while (++i < toFixedHelpers.size) { |
|
6195 c2 += n * toFixedHelpers.data[i]; |
|
6196 toFixedHelpers.data[i] = c2 % toFixedHelpers.base; |
|
6197 c2 = Math.floor(c2 / toFixedHelpers.base); |
|
6198 } |
|
6199 }, |
|
6200 divide: function divide(n) { |
|
6201 var i = toFixedHelpers.size, c = 0; |
|
6202 while (--i >= 0) { |
|
6203 c += toFixedHelpers.data[i]; |
|
6204 toFixedHelpers.data[i] = Math.floor(c / n); |
|
6205 c = (c % n) * toFixedHelpers.base; |
|
6206 } |
|
6207 }, |
|
6208 numToString: function numToString() { |
|
6209 var i = toFixedHelpers.size; |
|
6210 var s = ''; |
|
6211 while (--i >= 0) { |
|
6212 if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) { |
|
6213 var t = $String(toFixedHelpers.data[i]); |
|
6214 if (s === '') { |
|
6215 s = t; |
|
6216 } else { |
|
6217 s += strSlice('0000000', 0, 7 - t.length) + t; |
|
6218 } |
|
6219 } |
|
6220 } |
|
6221 return s; |
|
6222 }, |
|
6223 pow: function pow(x, n, acc) { |
|
6224 return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc))); |
|
6225 }, |
|
6226 log: function log(x) { |
|
6227 var n = 0; |
|
6228 var x2 = x; |
|
6229 while (x2 >= 4096) { |
|
6230 n += 12; |
|
6231 x2 /= 4096; |
|
6232 } |
|
6233 while (x2 >= 2) { |
|
6234 n += 1; |
|
6235 x2 /= 2; |
|
6236 } |
|
6237 return n; |
|
6238 } |
|
6239 }; |
|
6240 |
|
6241 defineProperties(NumberPrototype, { |
|
6242 toFixed: function toFixed(fractionDigits) { |
|
6243 var f, x, s, m, e, z, j, k; |
|
6244 |
|
6245 // Test for NaN and round fractionDigits down |
|
6246 f = $Number(fractionDigits); |
|
6247 f = f !== f ? 0 : Math.floor(f); |
|
6248 |
|
6249 if (f < 0 || f > 20) { |
|
6250 throw new RangeError('Number.toFixed called with invalid number of decimals'); |
|
6251 } |
|
6252 |
|
6253 x = $Number(this); |
|
6254 |
|
6255 // Test for NaN |
|
6256 if (x !== x) { |
|
6257 return 'NaN'; |
|
6258 } |
|
6259 |
|
6260 // If it is too big or small, return the string value of the number |
|
6261 if (x <= -1e21 || x >= 1e21) { |
|
6262 return $String(x); |
|
6263 } |
|
6264 |
|
6265 s = ''; |
|
6266 |
|
6267 if (x < 0) { |
|
6268 s = '-'; |
|
6269 x = -x; |
|
6270 } |
|
6271 |
|
6272 m = '0'; |
|
6273 |
|
6274 if (x > 1e-21) { |
|
6275 // 1e-21 < x < 1e21 |
|
6276 // -70 < log2(x) < 70 |
|
6277 e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69; |
|
6278 z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1)); |
|
6279 z *= 0x10000000000000; // Math.pow(2, 52); |
|
6280 e = 52 - e; |
|
6281 |
|
6282 // -18 < e < 122 |
|
6283 // x = z / 2 ^ e |
|
6284 if (e > 0) { |
|
6285 toFixedHelpers.multiply(0, z); |
|
6286 j = f; |
|
6287 |
|
6288 while (j >= 7) { |
|
6289 toFixedHelpers.multiply(1e7, 0); |
|
6290 j -= 7; |
|
6291 } |
|
6292 |
|
6293 toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0); |
|
6294 j = e - 1; |
|
6295 |
|
6296 while (j >= 23) { |
|
6297 toFixedHelpers.divide(1 << 23); |
|
6298 j -= 23; |
|
6299 } |
|
6300 |
|
6301 toFixedHelpers.divide(1 << j); |
|
6302 toFixedHelpers.multiply(1, 1); |
|
6303 toFixedHelpers.divide(2); |
|
6304 m = toFixedHelpers.numToString(); |
|
6305 } else { |
|
6306 toFixedHelpers.multiply(0, z); |
|
6307 toFixedHelpers.multiply(1 << (-e), 0); |
|
6308 m = toFixedHelpers.numToString() + strSlice('0.00000000000000000000', 2, 2 + f); |
|
6309 } |
|
6310 } |
|
6311 |
|
6312 if (f > 0) { |
|
6313 k = m.length; |
|
6314 |
|
6315 if (k <= f) { |
|
6316 m = s + strSlice('0.0000000000000000000', 0, f - k + 2) + m; |
|
6317 } else { |
|
6318 m = s + strSlice(m, 0, k - f) + '.' + strSlice(m, k - f); |
|
6319 } |
|
6320 } else { |
|
6321 m = s + m; |
|
6322 } |
|
6323 |
|
6324 return m; |
|
6325 } |
|
6326 }, hasToFixedBugs); |
|
6327 |
|
6328 // |
|
6329 // String |
|
6330 // ====== |
|
6331 // |
|
6332 |
|
6333 // ES5 15.5.4.14 |
|
6334 // http://es5.github.com/#x15.5.4.14 |
|
6335 |
|
6336 // [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers] |
|
6337 // Many browsers do not split properly with regular expressions or they |
|
6338 // do not perform the split correctly under obscure conditions. |
|
6339 // See http://blog.stevenlevithan.com/archives/cross-browser-split |
|
6340 // I've tested in many browsers and this seems to cover the deviant ones: |
|
6341 // 'ab'.split(/(?:ab)*/) should be ["", ""], not [""] |
|
6342 // '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""] |
|
6343 // 'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not |
|
6344 // [undefined, "t", undefined, "e", ...] |
|
6345 // ''.split(/.?/) should be [], not [""] |
|
6346 // '.'.split(/()()/) should be ["."], not ["", "", "."] |
|
6347 |
|
6348 if ( |
|
6349 'ab'.split(/(?:ab)*/).length !== 2 || |
|
6350 '.'.split(/(.?)(.?)/).length !== 4 || |
|
6351 'tesst'.split(/(s)*/)[1] === 't' || |
|
6352 'test'.split(/(?:)/, -1).length !== 4 || |
|
6353 ''.split(/.?/).length || |
|
6354 '.'.split(/()()/).length > 1 |
|
6355 ) { |
|
6356 (function () { |
|
6357 var compliantExecNpcg = typeof (/()??/).exec('')[1] === 'undefined'; // NPCG: nonparticipating capturing group |
|
6358 |
|
6359 StringPrototype.split = function (separator, limit) { |
|
6360 var string = this; |
|
6361 if (typeof separator === 'undefined' && limit === 0) { |
|
6362 return []; |
|
6363 } |
|
6364 |
|
6365 // If `separator` is not a regex, use native split |
|
6366 if (!isRegex(separator)) { |
|
6367 return strSplit(this, separator, limit); |
|
6368 } |
|
6369 |
|
6370 var output = []; |
|
6371 var flags = (separator.ignoreCase ? 'i' : '') + |
|
6372 (separator.multiline ? 'm' : '') + |
|
6373 (separator.unicode ? 'u' : '') + // in ES6 |
|
6374 (separator.sticky ? 'y' : ''), // Firefox 3+ and ES6 |
|
6375 lastLastIndex = 0, |
|
6376 // Make `global` and avoid `lastIndex` issues by working with a copy |
|
6377 separator2, match, lastIndex, lastLength; |
|
6378 var separatorCopy = new RegExp(separator.source, flags + 'g'); |
|
6379 string += ''; // Type-convert |
|
6380 if (!compliantExecNpcg) { |
|
6381 // Doesn't need flags gy, but they don't hurt |
|
6382 separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags); |
|
6383 } |
|
6384 /* Values for `limit`, per the spec: |
|
6385 * If undefined: 4294967295 // Math.pow(2, 32) - 1 |
|
6386 * If 0, Infinity, or NaN: 0 |
|
6387 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296; |
|
6388 * If negative number: 4294967296 - Math.floor(Math.abs(limit)) |
|
6389 * If other: Type-convert, then use the above rules |
|
6390 */ |
|
6391 var splitLimit = typeof limit === 'undefined' ? |
|
6392 -1 >>> 0 : // Math.pow(2, 32) - 1 |
|
6393 ES.ToUint32(limit); |
|
6394 match = separatorCopy.exec(string); |
|
6395 while (match) { |
|
6396 // `separatorCopy.lastIndex` is not reliable cross-browser |
|
6397 lastIndex = match.index + match[0].length; |
|
6398 if (lastIndex > lastLastIndex) { |
|
6399 array_push.call(output, strSlice(string, lastLastIndex, match.index)); |
|
6400 // Fix browsers whose `exec` methods don't consistently return `undefined` for |
|
6401 // nonparticipating capturing groups |
|
6402 if (!compliantExecNpcg && match.length > 1) { |
|
6403 /* eslint-disable no-loop-func */ |
|
6404 match[0].replace(separator2, function () { |
|
6405 for (var i = 1; i < arguments.length - 2; i++) { |
|
6406 if (typeof arguments[i] === 'undefined') { |
|
6407 match[i] = void 0; |
|
6408 } |
|
6409 } |
|
6410 }); |
|
6411 /* eslint-enable no-loop-func */ |
|
6412 } |
|
6413 if (match.length > 1 && match.index < string.length) { |
|
6414 array_push.apply(output, array_slice.call(match, 1)); |
|
6415 } |
|
6416 lastLength = match[0].length; |
|
6417 lastLastIndex = lastIndex; |
|
6418 if (output.length >= splitLimit) { |
|
6419 break; |
|
6420 } |
|
6421 } |
|
6422 if (separatorCopy.lastIndex === match.index) { |
|
6423 separatorCopy.lastIndex++; // Avoid an infinite loop |
|
6424 } |
|
6425 match = separatorCopy.exec(string); |
|
6426 } |
|
6427 if (lastLastIndex === string.length) { |
|
6428 if (lastLength || !separatorCopy.test('')) { |
|
6429 array_push.call(output, ''); |
|
6430 } |
|
6431 } else { |
|
6432 array_push.call(output, strSlice(string, lastLastIndex)); |
|
6433 } |
|
6434 return output.length > splitLimit ? strSlice(output, 0, splitLimit) : output; |
|
6435 }; |
|
6436 }()); |
|
6437 |
|
6438 // [bugfix, chrome] |
|
6439 // If separator is undefined, then the result array contains just one String, |
|
6440 // which is the this value (converted to a String). If limit is not undefined, |
|
6441 // then the output array is truncated so that it contains no more than limit |
|
6442 // elements. |
|
6443 // "0".split(undefined, 0) -> [] |
|
6444 } else if ('0'.split(void 0, 0).length) { |
|
6445 StringPrototype.split = function split(separator, limit) { |
|
6446 if (typeof separator === 'undefined' && limit === 0) { return []; } |
|
6447 return strSplit(this, separator, limit); |
|
6448 }; |
|
6449 } |
|
6450 |
|
6451 var str_replace = StringPrototype.replace; |
|
6452 var replaceReportsGroupsCorrectly = (function () { |
|
6453 var groups = []; |
|
6454 'x'.replace(/x(.)?/g, function (match, group) { |
|
6455 array_push.call(groups, group); |
|
6456 }); |
|
6457 return groups.length === 1 && typeof groups[0] === 'undefined'; |
|
6458 }()); |
|
6459 |
|
6460 if (!replaceReportsGroupsCorrectly) { |
|
6461 StringPrototype.replace = function replace(searchValue, replaceValue) { |
|
6462 var isFn = isCallable(replaceValue); |
|
6463 var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source); |
|
6464 if (!isFn || !hasCapturingGroups) { |
|
6465 return str_replace.call(this, searchValue, replaceValue); |
|
6466 } else { |
|
6467 var wrappedReplaceValue = function (match) { |
|
6468 var length = arguments.length; |
|
6469 var originalLastIndex = searchValue.lastIndex; |
|
6470 searchValue.lastIndex = 0; |
|
6471 var args = searchValue.exec(match) || []; |
|
6472 searchValue.lastIndex = originalLastIndex; |
|
6473 array_push.call(args, arguments[length - 2], arguments[length - 1]); |
|
6474 return replaceValue.apply(this, args); |
|
6475 }; |
|
6476 return str_replace.call(this, searchValue, wrappedReplaceValue); |
|
6477 } |
|
6478 }; |
|
6479 } |
|
6480 |
|
6481 // ECMA-262, 3rd B.2.3 |
|
6482 // Not an ECMAScript standard, although ECMAScript 3rd Edition has a |
|
6483 // non-normative section suggesting uniform semantics and it should be |
|
6484 // normalized across all browsers |
|
6485 // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE |
|
6486 var string_substr = StringPrototype.substr; |
|
6487 var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b'; |
|
6488 defineProperties(StringPrototype, { |
|
6489 substr: function substr(start, length) { |
|
6490 var normalizedStart = start; |
|
6491 if (start < 0) { |
|
6492 normalizedStart = max(this.length + start, 0); |
|
6493 } |
|
6494 return string_substr.call(this, normalizedStart, length); |
|
6495 } |
|
6496 }, hasNegativeSubstrBug); |
|
6497 |
|
6498 // ES5 15.5.4.20 |
|
6499 // whitespace from: http://es5.github.io/#x15.5.4.20 |
|
6500 var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + |
|
6501 '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + |
|
6502 '\u2029\uFEFF'; |
|
6503 var zeroWidth = '\u200b'; |
|
6504 var wsRegexChars = '[' + ws + ']'; |
|
6505 var trimBeginRegexp = new RegExp('^' + wsRegexChars + wsRegexChars + '*'); |
|
6506 var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + '*$'); |
|
6507 var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim()); |
|
6508 defineProperties(StringPrototype, { |
|
6509 // http://blog.stevenlevithan.com/archives/faster-trim-javascript |
|
6510 // http://perfectionkills.com/whitespace-deviations/ |
|
6511 trim: function trim() { |
|
6512 if (typeof this === 'undefined' || this === null) { |
|
6513 throw new TypeError("can't convert " + this + ' to object'); |
|
6514 } |
|
6515 return $String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, ''); |
|
6516 } |
|
6517 }, hasTrimWhitespaceBug); |
|
6518 |
|
6519 // ES-5 15.1.2.2 |
|
6520 if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) { |
|
6521 /* global parseInt: true */ |
|
6522 parseInt = (function (origParseInt) { |
|
6523 var hexRegex = /^0[xX]/; |
|
6524 return function parseInt(str, radix) { |
|
6525 var string = $String(str).trim(); |
|
6526 var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10); |
|
6527 return origParseInt(string, defaultedRadix); |
|
6528 }; |
|
6529 }(parseInt)); |
|
6530 } |
|
6531 |
|
6532 })); |
|
6533 |
|
6534 },{}],26:[function(_dereq_,module,exports){ |
|
6535 var arr = []; |
|
6536 var each = arr.forEach; |
|
6537 var slice = arr.slice; |
|
6538 |
|
6539 |
|
6540 module.exports = function(obj) { |
|
6541 each.call(slice.call(arguments, 1), function(source) { |
|
6542 if (source) { |
|
6543 for (var prop in source) { |
|
6544 obj[prop] = source[prop]; |
|
6545 } |
|
6546 } |
|
6547 }); |
|
6548 return obj; |
|
6549 }; |
|
6550 |
|
6551 },{}],27:[function(_dereq_,module,exports){ |
|
6552 module.exports = isFunction |
|
6553 |
|
6554 var toString = Object.prototype.toString |
|
6555 |
|
6556 function isFunction (fn) { |
|
6557 var string = toString.call(fn) |
|
6558 return string === '[object Function]' || |
|
6559 (typeof fn === 'function' && string !== '[object RegExp]') || |
|
6560 (typeof window !== 'undefined' && |
|
6561 // IE8 and below |
|
6562 (fn === window.setTimeout || |
|
6563 fn === window.alert || |
|
6564 fn === window.confirm || |
|
6565 fn === window.prompt)) |
|
6566 }; |
|
6567 |
|
6568 },{}],28:[function(_dereq_,module,exports){ |
|
6569 "use strict"; |
|
6570 |
|
6571 module.exports = function isObject(x) { |
|
6572 return typeof x === "object" && x !== null; |
|
6573 }; |
|
6574 |
|
6575 },{}],29:[function(_dereq_,module,exports){ |
|
6576 /*! |
|
6577 * $script.js JS loader & dependency manager |
|
6578 * https://github.com/ded/script.js |
|
6579 * (c) Dustin Diaz 2014 | License MIT |
|
6580 */ |
|
6581 |
|
6582 (function (name, definition) { |
|
6583 if (typeof module != 'undefined' && module.exports) module.exports = definition() |
|
6584 else if (typeof define == 'function' && define.amd) define(definition) |
|
6585 else this[name] = definition() |
|
6586 })('$script', function () { |
|
6587 var doc = document |
|
6588 , head = doc.getElementsByTagName('head')[0] |
|
6589 , s = 'string' |
|
6590 , f = false |
|
6591 , push = 'push' |
|
6592 , readyState = 'readyState' |
|
6593 , onreadystatechange = 'onreadystatechange' |
|
6594 , list = {} |
|
6595 , ids = {} |
|
6596 , delay = {} |
|
6597 , scripts = {} |
|
6598 , scriptpath |
|
6599 , urlArgs |
|
6600 |
|
6601 function every(ar, fn) { |
|
6602 for (var i = 0, j = ar.length; i < j; ++i) if (!fn(ar[i])) return f |
|
6603 return 1 |
|
6604 } |
|
6605 function each(ar, fn) { |
|
6606 every(ar, function (el) { |
|
6607 return !fn(el) |
|
6608 }) |
|
6609 } |
|
6610 |
|
6611 function $script(paths, idOrDone, optDone) { |
|
6612 paths = paths[push] ? paths : [paths] |
|
6613 var idOrDoneIsDone = idOrDone && idOrDone.call |
|
6614 , done = idOrDoneIsDone ? idOrDone : optDone |
|
6615 , id = idOrDoneIsDone ? paths.join('') : idOrDone |
|
6616 , queue = paths.length |
|
6617 function loopFn(item) { |
|
6618 return item.call ? item() : list[item] |
|
6619 } |
|
6620 function callback() { |
|
6621 if (!--queue) { |
|
6622 list[id] = 1 |
|
6623 done && done() |
|
6624 for (var dset in delay) { |
|
6625 every(dset.split('|'), loopFn) && !each(delay[dset], loopFn) && (delay[dset] = []) |
|
6626 } |
|
6627 } |
|
6628 } |
|
6629 setTimeout(function () { |
|
6630 each(paths, function loading(path, force) { |
|
6631 if (path === null) return callback() |
|
6632 path = !force && path.indexOf('.js') === -1 && !/^https?:\/\//.test(path) && scriptpath ? scriptpath + path + '.js' : path |
|
6633 if (scripts[path]) { |
|
6634 if (id) ids[id] = 1 |
|
6635 return (scripts[path] == 2) ? callback() : setTimeout(function () { loading(path, true) }, 0) |
|
6636 } |
|
6637 |
|
6638 scripts[path] = 1 |
|
6639 if (id) ids[id] = 1 |
|
6640 create(path, callback) |
|
6641 }) |
|
6642 }, 0) |
|
6643 return $script |
|
6644 } |
|
6645 |
|
6646 function create(path, fn) { |
|
6647 var el = doc.createElement('script'), loaded |
|
6648 el.onload = el.onerror = el[onreadystatechange] = function () { |
|
6649 if ((el[readyState] && !(/^c|loade/.test(el[readyState]))) || loaded) return; |
|
6650 el.onload = el[onreadystatechange] = null |
|
6651 loaded = 1 |
|
6652 scripts[path] = 2 |
|
6653 fn() |
|
6654 } |
|
6655 el.async = 1 |
|
6656 el.src = urlArgs ? path + (path.indexOf('?') === -1 ? '?' : '&') + urlArgs : path; |
|
6657 head.insertBefore(el, head.lastChild) |
|
6658 } |
|
6659 |
|
6660 $script.get = create |
|
6661 |
|
6662 $script.order = function (scripts, id, done) { |
|
6663 (function callback(s) { |
|
6664 s = scripts.shift() |
|
6665 !scripts.length ? $script(s, id, done) : $script(s, callback) |
|
6666 }()) |
|
6667 } |
|
6668 |
|
6669 $script.path = function (p) { |
|
6670 scriptpath = p |
|
6671 } |
|
6672 $script.urlArgs = function (str) { |
|
6673 urlArgs = str; |
|
6674 } |
|
6675 $script.ready = function (deps, ready, req) { |
|
6676 deps = deps[push] ? deps : [deps] |
|
6677 var missing = []; |
|
6678 !each(deps, function (dep) { |
|
6679 list[dep] || missing[push](dep); |
|
6680 }) && every(deps, function (dep) {return list[dep]}) ? |
|
6681 ready() : !function (key) { |
|
6682 delay[key] = delay[key] || [] |
|
6683 delay[key][push](ready) |
|
6684 req && req(missing) |
|
6685 }(deps.join('|')) |
|
6686 return $script |
|
6687 } |
|
6688 |
|
6689 $script.done = function (idOrDone) { |
|
6690 $script([null], idOrDone) |
|
6691 } |
|
6692 |
|
6693 return $script |
|
6694 }); |
|
6695 |
|
6696 },{}]},{},[19])(19) |
|
6697 }); |