Advertisement
Guest User

Scrollorama

a guest
Jan 8th, 2014
221
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.61 KB | None | 0 0
  1. /*
  2. scrollorama - The jQuery plugin for doing cool scrolly stuff
  3. by John Polacek (@johnpolacek)
  4.  
  5. Dual licensed under MIT and GPL.
  6. */
  7.  
  8.  
  9. (function($) {
  10. $.scrollorama = function(options) {
  11. var scrollorama = this,
  12. blocks = [],
  13. browserPrefix = '',
  14. ieVersion = '',
  15. onBlockChange = function() {},
  16. latestKnownScrollY = 0,
  17. ticking = false,
  18. requestAnimFrame = window.requestAnimationFrame ||
  19. window.webkitRequestAnimationFrame ||
  20. window.mozRequestAnimationFrame ||
  21. window.oRequestAnimationFrame ||
  22. window.msRequestAnimationFrame ||
  23. function( callback ){
  24. window.setTimeout(callback, 1000 / 60);
  25. },
  26. defaults = {offset:0, enablePin: true};
  27.  
  28. scrollorama.settings = $.extend({}, defaults, options);
  29. scrollorama.blockIndex = 0;
  30.  
  31. if (options.blocks === undefined) { alert('ERROR: Must assign blocks class selector to scrollorama plugin'); }
  32.  
  33. // PRIVATE FUNCTIONS
  34. function init() {
  35. var i, block, didScroll, marginTop = false;
  36. if (typeof scrollorama.settings.blocks === 'string') { scrollorama.settings.blocks = $(scrollorama.settings.blocks); }
  37.  
  38. // set browser prefix (using getBrowser based on jQuery’s $.browser)
  39. var browser = getBrowser();
  40. if (browser.mozilla) { browserPrefix = '-moz-'; }
  41. if (browser.webkit) { browserPrefix = '-webkit-'; }
  42. if (browser.opera) { browserPrefix = '-o-'; }
  43. if (browser.msie) {
  44. browserPrefix = '-ms-';
  45. ieVersion = parseInt(browser.version, 10);
  46. }
  47.  
  48. // create blocks array to contain animation props
  49. $('body').css('position','relative');
  50. for (i=0; i<scrollorama.settings.blocks.length; i++) {
  51. block = scrollorama.settings.blocks.eq(i);
  52. marginTop = block.css('margin-top');
  53. blocks.push({
  54. block: block,
  55. top: block.offset().top - (!Boolean(marginTop) ? parseInt(marginTop, 10) : 0),
  56. pin: 0,
  57. animations:[]
  58. });
  59. }
  60.  
  61. // convert block elements to absolute position
  62. if (scrollorama.settings.enablePin.toString() === 'true') {
  63. for (i=0; i<blocks.length; i++) {
  64. blocks[i].block
  65. .css('position', 'absolute')
  66. .css('top', blocks[i].top);
  67. }
  68. }
  69.  
  70. // create scroll-wrap div only once
  71. if ($("#scroll-wrap").length === 0) {
  72. $('body').prepend('<div id="scroll-wrap"></div>');
  73. }
  74.  
  75. latestKnownScrollY = 0;
  76. ticking = false;
  77. $(window).on( 'scroll.scrollorama', onScroll );
  78. }
  79.  
  80. function onScroll() {
  81. latestKnownScrollY = window.scrollY;
  82. requestTick();
  83. }
  84.  
  85. function requestTick() {
  86. if(!ticking) {
  87. requestAnimFrame(function(){
  88. onScrollorama();
  89. update();
  90. });
  91. }
  92. ticking = true;
  93. }
  94.  
  95. function update() {
  96. // reset the tick so we can
  97. // capture the next onScroll
  98. ticking = false;
  99. }
  100.  
  101. function onScrollorama() {
  102. var scrollTop = $(window).scrollTop(),
  103. currBlockIndex = getCurrBlockIndex(scrollTop),
  104. i, j, anim, startAnimPos, endAnimPos, animPercent, animVal;
  105.  
  106. // update all animations
  107. for (i=0; i<blocks.length; i++) {
  108.  
  109. // go through the animations for each block
  110. if (blocks[i].animations.length) {
  111. for (j=0; j<blocks[i].animations.length; j++) {
  112. anim = blocks[i].animations[j];
  113.  
  114. // if above current block, settings should be at start value
  115. if (i > currBlockIndex) {
  116. if (currBlockIndex !== i-1 && anim.baseline !== 'bottom') {
  117. setProperty(anim, anim.startVal);
  118. }
  119. if (blocks[i].pin) {
  120. blocks[i].block
  121. .css('position', 'absolute')
  122. .css('top', blocks[i].top);
  123. }
  124. }
  125.  
  126. // if below current block, settings should be at end value
  127. // unless on an element that gets animated when it hits the bottom of the viewport
  128. else if (i < currBlockIndex) {
  129. setProperty(anim, anim.endVal);
  130. if (blocks[i].pin) {
  131. blocks[i].block
  132. .css('position', 'absolute')
  133. .css('top', (blocks[i].top + blocks[i].pin));
  134. }
  135. }
  136.  
  137. // otherwise, set values per scroll position
  138. if (i === currBlockIndex || (currBlockIndex === i-1 && anim.baseline === 'bottom')) {
  139. // if block gets pinned, set position fixed
  140. if (blocks[i].pin && currBlockIndex === i) {
  141. blocks[i].block
  142. .css('position', 'fixed')
  143. .css('top', 0);
  144. }
  145.  
  146. // set start and end animation positions
  147. startAnimPos = blocks[i].top + anim.delay;
  148. if (anim.baseline === 'bottom') { startAnimPos -= $(window).height(); }
  149. endAnimPos = startAnimPos + anim.duration;
  150.  
  151. // if scroll is before start of animation, set to start value
  152. if (scrollTop < startAnimPos) {
  153. setProperty(anim, anim.startVal);
  154. }
  155.  
  156. // if scroll is after end of animation, set to end value
  157. else if (scrollTop > endAnimPos) {
  158. setProperty(anim, anim.endVal);
  159. if (blocks[i].pin) {
  160. blocks[i].block
  161. .css('position', 'absolute')
  162. .css('top', (blocks[i].top + blocks[i].pin));
  163. }
  164. }
  165.  
  166. // otherwise, set value based on scroll
  167. else {
  168. // calculate percent to animate
  169. animPercent = (scrollTop - startAnimPos) / anim.duration;
  170. // account for easing if there is any
  171. if ( anim.easing && $.isFunction( $.easing[anim.easing] ) ) {
  172. animPercent = $.easing[anim.easing]( animPercent, animPercent*1000, 0, 1, 1000 );
  173. }
  174. // then multiply the percent by the value range and calculate the new value
  175. animVal = anim.startVal + (animPercent * (anim.endVal - anim.startVal));
  176. setProperty(anim, animVal);
  177. }
  178. }
  179. }
  180. }
  181. }
  182.  
  183. // update blockIndex and trigger event if changed
  184. if (scrollorama.blockIndex !== currBlockIndex) {
  185. scrollorama.blockIndex = currBlockIndex;
  186. onBlockChange();
  187. }
  188. }
  189.  
  190. function getCurrBlockIndex(scrollTop) {
  191. var currBlockIndex = 0, i;
  192. for (i=0; i<blocks.length; i++) {
  193. // check if block is in view
  194. if (blocks[i].top <= scrollTop - scrollorama.settings.offset) { currBlockIndex = i; }
  195. }
  196. return currBlockIndex;
  197. }
  198.  
  199. function setProperty(anim, val) {
  200. var target = anim.element;
  201. var prop = anim.property;
  202. var scaleCSS, currentPosition;
  203. if (prop === 'rotate' || prop === 'zoom' || prop === 'scale') {
  204. if (prop === 'rotate') {
  205. target.css(browserPrefix+'transform', 'rotate('+val+'deg)');
  206. } else if (prop === 'zoom' || prop === 'scale') {
  207. scaleCSS = 'scale('+val+')';
  208. if (browserPrefix !== '-ms-') {
  209. target.css(browserPrefix+'transform', scaleCSS);
  210. } else {
  211. if (jQuery().scale) $(target.selector).scale(val);
  212. target.css('zoom', val);
  213. }
  214. }
  215. }
  216. else if(prop === 'background-position-x' || prop === 'background-position-y' ) {
  217. currentPosition = target.css('background-position').split(' ');
  218. if(prop === 'background-position-x') {
  219. target.css('background-position',val+'px '+currentPosition[1]);
  220. }
  221. if(prop === 'background-position-y') {
  222. target.css('background-position', currentPosition[0]+' '+val+'px');
  223. }
  224. }
  225. else if(prop === 'text-shadow' ) {
  226. target.css(prop,'0px 0px '+val+'px #ffffff');
  227. } else {
  228. if (anim.suffix) {
  229. target.css(prop, val + anim.suffix);
  230. } else {
  231. target.css(prop, val);
  232. }
  233. }
  234. }
  235.  
  236.  
  237. // PUBLIC FUNCTIONS
  238. scrollorama.animate = function(target) {
  239. var targetIndex,
  240. targetBlock,
  241. anim,
  242. offset,
  243. suffix,
  244. i, j;
  245. /*
  246. target = animation target
  247. arguments = array of animation parameters
  248. anim = object that contains all animation params (created from arguments)
  249. offset = positioning helper for pinning
  250.  
  251. animation parameters:
  252. delay = amount of scrolling (in pixels) before animation starts
  253. duration = amount of scrolling (in pixels) over which the animation occurs
  254. property = css property being animated
  255. start = start value of the property
  256. end = end value of the property
  257. pin = pin block during animation duration (applies to all animations within block)
  258. baseline = top (default, when block reaches top of viewport) or bottom (when block first comies into view)
  259. easing = just like jquery's easing functions
  260. */
  261.  
  262. // if string, convert to DOM object
  263. if (typeof target === 'string') { target = $(target); }
  264.  
  265. // find block of target
  266. for (i=0; i<blocks.length; i++) {
  267. if (blocks[i].block.has(target).length) {
  268. targetBlock = blocks[i];
  269. targetIndex = i;
  270. }
  271. }
  272.  
  273. // add each animation to the blocks animations array from function arguments
  274. for (i=1; i<arguments.length; i++) {
  275.  
  276. anim = arguments[i];
  277.  
  278. // for top/left/right/bottom, set relative positioning if static
  279. if (anim.property === 'top' || anim.property === 'left' || anim.property === 'bottom' || anim.property === 'right' ) {
  280. if (target.css('position') === 'static') { target.css('position','relative'); }
  281. // set anim.start, anim.end defaults
  282. cssValue = parseInt(target.css(anim.property),10);
  283. if (anim.start === undefined) {
  284. anim.start = isNaN(cssValue) ? 0 : cssValue;
  285. } else if (anim.end === undefined) {
  286. anim.end = isNaN(cssValue) ? 0 : cssValue;
  287. }
  288. }
  289.  
  290. // set anim.start/anim.end defaults for rotate, zoom/scale, letter-spacing
  291. if (anim.property === 'rotate') {
  292. if (anim.start === undefined) { anim.start = 0; }
  293. if (anim.end === undefined) { anim.end = 0; }
  294. } else if (anim.property === 'zoom' || anim.property === 'scale' ) {
  295. if (anim.start === undefined) { anim.start = 1; }
  296. if (anim.end === undefined) { anim.end = 1; }
  297. } else if (anim.property === 'letter-spacing' && target.css(anim.property)) {
  298. if (anim.start === undefined) { anim.start = 1; }
  299. if (anim.end === undefined) { anim.end = 1; }
  300. }
  301.  
  302. // convert background-position property for use on IE8 and lower
  303. if (ieVersion && ieVersion < 9 && (anim.property == 'background-position-x' || anim.property == 'background-position-y')) {
  304. if (anim.property === 'background-position-x') {
  305. anim.property = 'backgroundPositionX';
  306. }
  307. else {
  308. anim.property = 'backgroundPositionY';
  309. }
  310. }
  311.  
  312. if (anim.baseline === undefined) {
  313. if (anim.pin || targetBlock.pin || targetIndex === 0) {
  314. anim.baseline = 'top';
  315. } else {
  316. anim.baseline = 'bottom';
  317. }
  318. }
  319.  
  320. if (anim.delay === undefined) { anim.delay = 0; }
  321.  
  322. startVal = anim.start !== undefined ? typeof(anim.start) == 'function' ? anim.start() : anim.start : parseInt(target.css(anim.property),10); // if undefined, use current css value
  323. endVal = anim.end !== undefined ? typeof(anim.end) == 'function' ? anim.end() : anim.end : parseInt(target.css(anim.property),10); // if undefined, use current css value
  324. suffix = startVal.toString().match(/\D+$/) || endVal.toString().match(/\D+$/);
  325. if (suffix) {
  326. suffix = suffix[0];
  327. startVal = parseInt(startVal,10); // remove the unit so calculations work correctly
  328. endVal = parseInt(endVal,10);
  329. }
  330.  
  331. targetBlock.animations.push({
  332. element: target,
  333. delay: anim.delay,
  334. duration: anim.duration,
  335. property: anim.property,
  336. startVal: startVal,
  337. endVal: endVal,
  338. suffix: suffix,
  339. baseline: anim.baseline !== undefined ? anim.baseline : 'bottom',
  340. easing: anim.easing
  341. });
  342.  
  343. if (anim.pin) {
  344. if (targetBlock.pin < anim.duration + anim.delay) {
  345. offset = anim.duration + anim.delay - targetBlock.pin;
  346. targetBlock.pin += offset;
  347.  
  348. // adjust positions of blocks below target block
  349. for (j=targetIndex+1; j<blocks.length; j++) {
  350. blocks[j].top += offset;
  351. blocks[j].block.css('top', blocks[j].top);
  352. }
  353. }
  354. }
  355. }
  356.  
  357. onScrollorama();
  358.  
  359. return scrollorama;
  360. };
  361.  
  362. // function for passing blockChange event callback
  363. scrollorama.onBlockChange = function(f) {
  364. onBlockChange = f;
  365. };
  366.  
  367. // function for getting an array of scrollpoints
  368. // (top of each animation block and animation element scroll start point)
  369. scrollorama.getScrollpoints = function() {
  370. var scrollpoints = [],i,j,anim;
  371. for (i=0; i<blocks.length; i++) {
  372. scrollpoints.push(blocks[i].top);
  373. // go through the animations for each block
  374. if (blocks[i].animations.length && blocks[i].pin > 0) {
  375. for (j=0; j<blocks[i].animations.length; j++) {
  376. anim = blocks[i].animations[j];
  377. scrollpoints.push(blocks[i].top + anim.delay + anim.duration);
  378. }
  379. }
  380. }
  381. // make sure scrollpoints are in numeric order
  382. scrollpoints.sort(function(a,b) {return a - b;});
  383. return scrollpoints;
  384. };
  385.  
  386. // Remove scrollorama
  387. scrollorama.destroy = function () {
  388. // Remove animations
  389. for (i=0; i<blocks.length; i++) {
  390. // Remove CSS rules
  391. blocks[i].block.css({
  392. top: '',
  393. position: ''
  394. });
  395.  
  396. // Remove scrolloroma-specific attributes
  397. delete blocks[i].animations;
  398. delete blocks[i].top;
  399. delete blocks[i].pin;
  400. }
  401. //add the following:
  402. scrollorama.blocks = blocks;
  403. var thirdWindowHeight = Math.round(windowObj.height / 3),
  404. bannerHeight = $wrapper.find(".thediv").height(),
  405. dragDuration = $body.find("#page").height(),
  406. headerHeight = $body.find("#masthead-wrap").height(),
  407. delay = bannerHeight - headerHeight,
  408. animations,
  409. animation;
  410.  
  411. for (var i = 0, j = this.scrollorama.blocks.length; i < j; i++) {
  412.  
  413. animations = this.scrollorama.blocks[i].animations;
  414.  
  415. for (var k = 0, l = animations.length; k < l; k++) {
  416. animation = animations[k];
  417.  
  418. $wrapper.find(animation["element"].selector).removeAttr("style");
  419.  
  420. switch (animation["element"].selector) {
  421. case ".thediv":
  422. animation.endVal = thirdWindowHeight;
  423. animation.duration = bannerHeight;
  424. break;
  425.  
  426. case ".drag":
  427. animation.delay = delay;
  428. animation.duration = dragDuration;
  429. animation.endVal = dragDuration;
  430. break;
  431. }
  432. }
  433. }
  434.  
  435. $(window).triggerHandler("scroll");
  436.  
  437. // Unbind the window scroll event
  438. $(window).off('scroll.scrollorama');
  439. $('#scroll-wrap').remove();
  440.  
  441. // Remove the scrolloroma object
  442. delete scrollorama;
  443. };
  444.  
  445. init();
  446.  
  447. return scrollorama;
  448. };
  449.  
  450. // Easing functions from jQuery UI
  451. $.extend($.easing, {
  452. def: 'easeOutQuad',
  453. swing: function (x, t, b, c, d) {
  454. //alert($.easing.default);
  455. return $.easing[$.easing.def](x, t, b, c, d);
  456. },
  457. easeInQuad: function (x, t, b, c, d) {
  458. return c*(t/=d)*t + b;
  459. },
  460. easeOutQuad: function (x, t, b, c, d) {
  461. return -c *(t/=d)*(t-2) + b;
  462. },
  463. easeInOutQuad: function (x, t, b, c, d) {
  464. if ((t/=d/2) < 1) { return c/2*t*t + b; }
  465. return -c/2 * ((--t)*(t-2) - 1) + b;
  466. },
  467. easeInCubic: function (x, t, b, c, d) {
  468. return c*(t/=d)*t*t + b;
  469. },
  470. easeOutCubic: function (x, t, b, c, d) {
  471. return c*((t=t/d-1)*t*t + 1) + b;
  472. },
  473. easeInOutCubic: function (x, t, b, c, d) {
  474. if ((t/=d/2) < 1) { return c/2*t*t*t + b; }
  475. return c/2*((t-=2)*t*t + 2) + b;
  476. },
  477. easeInQuart: function (x, t, b, c, d) {
  478. return c*(t/=d)*t*t*t + b;
  479. },
  480. easeOutQuart: function (x, t, b, c, d) {
  481. return -c * ((t=t/d-1)*t*t*t - 1) + b;
  482. },
  483. easeInOutQuart: function (x, t, b, c, d) {
  484. if ((t/=d/2) < 1) { return c/2*t*t*t*t + b; }
  485. return -c/2 * ((t-=2)*t*t*t - 2) + b;
  486. },
  487. easeInQuint: function (x, t, b, c, d) {
  488. return c*(t/=d)*t*t*t*t + b;
  489. },
  490. easeOutQuint: function (x, t, b, c, d) {
  491. return c*((t=t/d-1)*t*t*t*t + 1) + b;
  492. },
  493. easeInOutQuint: function (x, t, b, c, d) {
  494. if ((t/=d/2) < 1) { return c/2*t*t*t*t*t + b; }
  495. return c/2*((t-=2)*t*t*t*t + 2) + b;
  496. },
  497. easeInSine: function (x, t, b, c, d) {
  498. return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
  499. },
  500. easeOutSine: function (x, t, b, c, d) {
  501. return c * Math.sin(t/d * (Math.PI/2)) + b;
  502. },
  503. easeInOutSine: function (x, t, b, c, d) {
  504. return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
  505. },
  506. easeInExpo: function (x, t, b, c, d) {
  507. return (t===0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
  508. },
  509. easeOutExpo: function (x, t, b, c, d) {
  510. return (t===d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
  511. },
  512. easeInOutExpo: function (x, t, b, c, d) {
  513. if (t===0) { return b; }
  514. if (t===d) { return b+c; }
  515. if ((t/=d/2) < 1) { return c/2 * Math.pow(2, 10 * (t - 1)) + b; }
  516. return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
  517. },
  518. easeInCirc: function (x, t, b, c, d) {
  519. return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
  520. },
  521. easeOutCirc: function (x, t, b, c, d) {
  522. return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
  523. },
  524. easeInOutCirc: function (x, t, b, c, d) {
  525. if ((t/=d/2) < 1) { return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; }
  526. return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
  527. },
  528. easeInElastic: function (x, t, b, c, d) {
  529. var s=1.70158,p=0,a=c;
  530. if (t===0) { return b; }
  531. if ((t/=d)===1) { return b+c; }
  532. if (!p) { p=d*0.3; }
  533. if (a < Math.abs(c)) { a=c; s=p/4; }
  534. else{ s = p/(2*Math.PI) * Math.asin (c/a); }
  535. return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
  536. },
  537. easeOutElastic: function (x, t, b, c, d) {
  538. var s=1.70158,p=0,a=c;
  539. if (t===0) { return b; }
  540. if ((t/=d)===1) { return b+c; }
  541. if (!p) { p=d*0.3; }
  542. if (a < Math.abs(c)) { a=c; s=p/4; }
  543. else { s = p/(2*Math.PI) * Math.asin (c/a); }
  544. return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
  545. },
  546. easeInOutElastic: function (x, t, b, c, d) {
  547. var s=1.70158,p=0,a=c;
  548. if (t===0) { return b; }
  549. if ((t/=d/2)===2) { return b+c; }
  550. if (!p) { p=d*(0.3*1.5); }
  551. if (a < Math.abs(c)) { a=c; s=p/4; }
  552. else { s = p/(2*Math.PI) * Math.asin (c/a); }
  553. if (t < 1) { return -0.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; }
  554. return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
  555. },
  556. easeInBack: function (x, t, b, c, d, s) {
  557. if (s === undefined) { s = 1.70158; }
  558. return c*(t/=d)*t*((s+1)*t - s) + b;
  559. },
  560. easeOutBack: function (x, t, b, c, d, s) {
  561. if (s === undefined) { s = 1.70158; }
  562. return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
  563. },
  564. easeInOutBack: function (x, t, b, c, d, s) {
  565. if (s === undefined) { s = 1.70158; }
  566. if ((t/=d/2) < 1) { return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; }
  567. return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
  568. },
  569. easeInBounce: function (x, t, b, c, d) {
  570. return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b;
  571. },
  572. easeOutBounce: function (x, t, b, c, d) {
  573. if ((t/=d) < (1/2.75)) {
  574. return c*(7.5625*t*t) + b;
  575. } else if (t < (2/2.75)) {
  576. return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
  577. } else if (t < (2.5/2.75)) {
  578. return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
  579. } else {
  580. return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
  581. }
  582. },
  583. easeInOutBounce: function (x, t, b, c, d) {
  584. if (t < d/2) { return $.easing.easeInBounce (x, t*2, 0, c, d) * 0.5 + b; }
  585. return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
  586. }
  587. });
  588.  
  589. })(jQuery);
  590.  
  591. /*!
  592. * Modified from: jQuery Migrate - v1.1.0 - 2013-01-31
  593. * https://github.com/jquery/jquery-migrate
  594. * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
  595. */
  596. function getBrowser() {
  597. var matched = uaMatch( navigator.userAgent );
  598. var browser = {};
  599. if ( matched.browser ) {
  600. browser[ matched.browser ] = true;
  601. browser.version = matched.version;
  602. }
  603. // Chrome is Webkit, but Webkit is also Safari.
  604. if ( browser.chrome ) {
  605. browser.webkit = true;
  606. } else if ( browser.webkit ) {
  607. browser.safari = true;
  608. }
  609. return browser;
  610. }
  611.  
  612. function uaMatch(ua) {
  613. ua = ua.toLowerCase();
  614.  
  615. var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
  616. /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
  617. /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
  618. /(msie) ([\w.]+)/.exec( ua ) ||
  619. ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
  620. [];
  621.  
  622. return {
  623. browser: match[ 1 ] || "",
  624. version: match[ 2 ] || "0"
  625. };
  626. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement