1; 2/** 3 * @license MIT or GPL-2.0 4 * @fileOverview Favico animations 5 * @author Miroslav Magda, http://blog.ejci.net 6 * @version 0.3.10 7 */ 8 9/** 10 * Create new favico instance 11 * @param {Object} Options 12 * @return {Object} Favico object 13 * @example 14 * var favico = new Favico({ 15 * bgColor : '#d00', 16 * textColor : '#fff', 17 * fontFamily : 'sans-serif', 18 * fontStyle : 'bold', 19 * position : 'down', 20 * type : 'circle', 21 * animation : 'slide', 22 * dataUrl: function(url){}, 23 * win: top 24 * }); 25 */ 26(function () { 27 28 var Favico = (function (opt) { 29 'use strict'; 30 opt = (opt) ? opt : {}; 31 var _def = { 32 bgColor: '#d00', 33 textColor: '#fff', 34 fontFamily: 'sans-serif', //Arial,Verdana,Times New Roman,serif,sans-serif,... 35 fontStyle: 'bold', //normal,italic,oblique,bold,bolder,lighter,100,200,300,400,500,600,700,800,900 36 type: 'circle', 37 position: 'down', // down, up, left, leftup (upleft) 38 animation: 'slide', 39 elementId: false, 40 dataUrl: false, 41 win: window 42 }; 43 var _opt, _orig, _h, _w, _canvas, _context, _img, _ready, _lastBadge, _running, _readyCb, _stop, _browser, _animTimeout, _drawTimeout, _doc; 44 45 _browser = {}; 46 _browser.ff = typeof InstallTrigger != 'undefined'; 47 _browser.chrome = !!window.chrome; 48 _browser.opera = !!window.opera || navigator.userAgent.indexOf('Opera') >= 0; 49 _browser.ie = /*@cc_on!@*/false; 50 _browser.safari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0; 51 _browser.supported = (_browser.chrome || _browser.ff || _browser.opera); 52 53 var _queue = []; 54 _readyCb = function () { 55 }; 56 _ready = _stop = false; 57 /** 58 * Initialize favico 59 */ 60 var init = function () { 61 //merge initial options 62 _opt = merge(_def, opt); 63 _opt.bgColor = hexToRgb(_opt.bgColor); 64 _opt.textColor = hexToRgb(_opt.textColor); 65 _opt.position = _opt.position.toLowerCase(); 66 _opt.animation = (animation.types['' + _opt.animation]) ? _opt.animation : _def.animation; 67 68 _doc = _opt.win.document; 69 70 var isUp = _opt.position.indexOf('up') > -1; 71 var isLeft = _opt.position.indexOf('left') > -1; 72 73 //transform the animations 74 if (isUp || isLeft) { 75 for (var a in animation.types) { 76 for (var i = 0; i < animation.types[a].length; i++) { 77 var step = animation.types[a][i]; 78 79 if (isUp) { 80 if (step.y < 0.6) { 81 step.y = step.y - 0.4; 82 } else { 83 step.y = step.y - 2 * step.y + (1 - step.w); 84 } 85 } 86 87 if (isLeft) { 88 if (step.x < 0.6) { 89 step.x = step.x - 0.4; 90 } else { 91 step.x = step.x - 2 * step.x + (1 - step.h); 92 } 93 } 94 95 animation.types[a][i] = step; 96 } 97 } 98 } 99 _opt.type = (type['' + _opt.type]) ? _opt.type : _def.type; 100 101 _orig = link.getIcon(); 102 //create temp canvas 103 _canvas = document.createElement('canvas'); 104 //create temp image 105 _img = document.createElement('img'); 106 if (_orig.hasAttribute('href')) { 107 _img.setAttribute('crossOrigin', 'anonymous'); 108 //get width/height 109 _img.onload = function () { 110 _h = (_img.height > 0) ? _img.height : 32; 111 _w = (_img.width > 0) ? _img.width : 32; 112 _canvas.height = _h; 113 _canvas.width = _w; 114 _context = _canvas.getContext('2d'); 115 icon.ready(); 116 }; 117 _img.setAttribute('src', _orig.getAttribute('href')); 118 } else { 119 _img.onload = function () { 120 _h = 32; 121 _w = 32; 122 _img.height = _h; 123 _img.width = _w; 124 _canvas.height = _h; 125 _canvas.width = _w; 126 _context = _canvas.getContext('2d'); 127 icon.ready(); 128 }; 129 _img.setAttribute('src', ''); 130 } 131 132 }; 133 /** 134 * Icon namespace 135 */ 136 var icon = {}; 137 /** 138 * Icon is ready (reset icon) and start animation (if ther is any) 139 */ 140 icon.ready = function () { 141 _ready = true; 142 icon.reset(); 143 _readyCb(); 144 }; 145 /** 146 * Reset icon to default state 147 */ 148 icon.reset = function () { 149 //reset 150 if (!_ready) { 151 return; 152 } 153 _queue = []; 154 _lastBadge = false; 155 _running = false; 156 _context.clearRect(0, 0, _w, _h); 157 _context.drawImage(_img, 0, 0, _w, _h); 158 //_stop=true; 159 link.setIcon(_canvas); 160 //webcam('stop'); 161 //video('stop'); 162 window.clearTimeout(_animTimeout); 163 window.clearTimeout(_drawTimeout); 164 }; 165 /** 166 * Start animation 167 */ 168 icon.start = function () { 169 if (!_ready || _running) { 170 return; 171 } 172 var finished = function () { 173 _lastBadge = _queue[0]; 174 _running = false;
175 if (_queue.length > 0) { 176 _queue.shift(); 177 icon.start(); 178 } else { 179 180 } 181 }; 182 if (_queue.length > 0) { 183 _running = true; 184 var run = function () { 185 // apply options for this animation 186 ['type', 'animation', 'bgColor', 'textColor', 'fontFamily', 'fontStyle'].forEach(function (a) { 187 if (a in _queue[0].options) { 188 _opt[a] = _queue[0].options[a]; 189 } 190 }); 191 animation.run(_queue[0].options, function () { 192 finished(); 193 }, false); 194 }; 195 if (_lastBadge) { 196 animation.run(_lastBadge.options, function () { 197 run(); 198 }, true); 199 } else { 200 run(); 201 } 202 } 203 }; 204 205 /** 206 * Badge types 207 */ 208 var type = {}; 209 var options = function (opt) { 210 opt.n = ((typeof opt.n) === 'number') ? Math.abs(opt.n | 0) : opt.n; 211 opt.x = _w * opt.x; 212 opt.y = _h * opt.y; 213 opt.w = _w * opt.w; 214 opt.h = _h * opt.h; 215 opt.len = ("" + opt.n).length; 216 return opt; 217 }; 218 /** 219 * Generate circle 220 * @param {Object} opt Badge options 221 */ 222 type.circle = function (opt) { 223 opt = options(opt); 224 var more = false; 225 if (opt.len === 2) { 226 opt.x = opt.x - opt.w * 0.4; 227 opt.w = opt.w * 1.4; 228 more = true; 229 } else if (opt.len >= 3) { 230 opt.x = opt.x - opt.w * 0.65; 231 opt.w = opt.w * 1.65; 232 more = true; 233 } 234 _context.clearRect(0, 0, _w, _h); 235 _context.drawImage(_img, 0, 0, _w, _h); 236 _context.beginPath(); 237 _context.font = _opt.fontStyle + " " + Math.floor(opt.h * (opt.n > 99 ? 0.85 : 1)) + "px " + _opt.fontFamily; 238 _context.textAlign = 'center'; 239 if (more) { 240 _context.moveTo(opt.x + opt.w / 2, opt.y); 241 _context.lineTo(opt.x + opt.w - opt.h / 2, opt.y); 242 _context.quadraticCurveTo(opt.x + opt.w, opt.y, opt.x + opt.w, opt.y + opt.h / 2); 243 _context.lineTo(opt.x + opt.w, opt.y + opt.h - opt.h / 2); 244 _context.quadraticCurveTo(opt.x + opt.w, opt.y + opt.h, opt.x + opt.w - opt.h / 2, opt.y + opt.h); 245 _context.lineTo(opt.x + opt.h / 2, opt.y + opt.h); 246 _context.quadraticCurveTo(opt.x, opt.y + opt.h, opt.x, opt.y + opt.h - opt.h / 2); 247 _context.lineTo(opt.x, opt.y + opt.h / 2); 248 _context.quadraticCurveTo(opt.x, opt.y, opt.x + opt.h / 2, opt.y); 249 } else { 250 _context.arc(opt.x + opt.w / 2, opt.y + opt.h / 2, opt.h / 2, 0, 2 * Math.PI); 251 } 252 _context.fillStyle = 'rgba(' + _opt.bgColor.r + ',' + _opt.bgColor.g + ',' + _opt.bgColor.b + ',' + opt.o + ')'; 253 _context.fill(); 254 _context.closePath(); 255 _context.beginPath(); 256 _context.stroke(); 257 _context.fillStyle = 'rgba(' + _opt.textColor.r + ',' + _opt.textColor.g + ',' + _opt.textColor.b + ',' + opt.o + ')'; 258 //_context.fillText((more) ? '9+' : opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15)); 259 if ((typeof opt.n) === 'number' && opt.n > 999) { 260 _context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000)) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2)); 261 } else { 262 _context.fillText(opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15)); 263 } 264 _context.closePath(); 265 }; 266 /** 267 * Generate rectangle 268 * @param {Object} opt Badge options 269 */ 270 type.rectangle = function (opt) { 271 opt = options(opt); 272 var more = false; 273 if (opt.len === 2) { 274 opt.x = opt.x - opt.w * 0.4; 275 opt.w = opt.w * 1.4; 276 more = true; 277 } else if (opt.len >= 3) { 278 opt.x = opt.x - opt.w * 0.65; 279 opt.w = opt.w * 1.65; 280 more = true; 281 } 282 _context.clearRect(0, 0, _w, _h); 283 _context.drawImage(_img, 0, 0, _w, _h); 284 _context.beginPath(); 285 _context.font = _opt.fontStyle + " " + Math.floor(opt.h * (opt.n > 99 ? 0.9 : 1)) + "px " + _opt.fontFamily; 286 _context.textAlign = 'center'; 287 _context.fillStyle = 'rgba(' + _opt.bgColor.r + ',' + _opt.bgColor.g + ',' + _opt.bgColor.b + ',' + opt.o + ')'; 288 _context.fillRect(opt.x, opt.y, opt.w, opt.h); 289 _context.fillStyle = 'rgba(' + _opt.textColor.r + ',' + _opt.textColor.g + ',' + _opt.textColor.b + ',' + opt.o + ')'; 290 //_context.fillText((more) ? '9+' : opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15)); 291 if ((typeof opt.n) === 'number' && opt.n > 999) {
292 _context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000)) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2)); 293 } else { 294 _context.fillText(opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15)); 295 } 296 _context.closePath(); 297 }; 298 299 /** 300 * Set badge 301 */ 302 var badge = function (number, opts) { 303 opts = ((typeof opts) === 'string' ? { 304 animation: opts 305 } : opts) || {}; 306 _readyCb = function () { 307 try { 308 if (typeof (number) === 'number' ? (number > 0) : (number !== '')) { 309 var q = { 310 type: 'badge', 311 options: { 312 n: number 313 } 314 }; 315 if ('animation' in opts && animation.types['' + opts.animation]) { 316 q.options.animation = '' + opts.animation; 317 } 318 if ('type' in opts && type['' + opts.type]) { 319 q.options.type = '' + opts.type; 320 } 321 ['bgColor', 'textColor'].forEach(function (o) { 322 if (o in opts) { 323 q.options[o] = hexToRgb(opts[o]); 324 } 325 }); 326 ['fontStyle', 'fontFamily'].forEach(function (o) { 327 if (o in opts) { 328 q.options[o] = opts[o]; 329 } 330 }); 331 _queue.push(q); 332 if (_queue.length > 100) { 333 throw new Error('Too many badges requests in queue.'); 334 } 335 icon.start(); 336 } else { 337 icon.reset(); 338 } 339 } catch (e) { 340 throw new Error('Error setting badge. Message: ' + e.message); 341 } 342 }; 343 if (_ready) { 344 _readyCb(); 345 } 346 }; 347 348 /** 349 * Set image as icon 350 */ 351 var image = function (imageElement) { 352 _readyCb = function () { 353 try { 354 var w = imageElement.width; 355 var h = imageElement.height; 356 var newImg = document.createElement('img'); 357 var ratio = (w / _w < h / _h) ? (w / _w) : (h / _h); 358 newImg.setAttribute('crossOrigin', 'anonymous'); 359 newImg.onload=function(){ 360 _context.clearRect(0, 0, _w, _h); 361 _context.drawImage(newImg, 0, 0, _w, _h); 362 link.setIcon(_canvas); 363 }; 364 newImg.setAttribute('src', imageElement.getAttribute('src')); 365 newImg.height = (h / ratio); 366 newImg.width = (w / ratio); 367 } catch (e) { 368 throw new Error('Error setting image. Message: ' + e.message); 369 } 370 }; 371 if (_ready) { 372 _readyCb(); 373 } 374 }; 375 /** 376 * Set video as icon 377 */ 378 var video = function (videoElement) { 379 _readyCb = function () { 380 try { 381 if (videoElement === 'stop') { 382 _stop = true; 383 icon.reset(); 384 _stop = false; 385 return; 386 } 387 //var w = videoElement.width; 388 //var h = videoElement.height; 389 //var ratio = (w / _w < h / _h) ? (w / _w) : (h / _h); 390 videoElement.addEventListener('play', function () { 391 drawVideo(this); 392 }, false); 393 394 } catch (e) { 395 throw new Error('Error setting video. Message: ' + e.message); 396 } 397 }; 398 if (_ready) { 399 _readyCb(); 400 } 401 }; 402 /** 403 * Set video as icon 404 */ 405 var webcam = function (action) { 406 //UR 407 if (!window.URL || !window.URL.createObjectURL) { 408 window.URL = window.URL || {}; 409 window.URL.createObjectURL = function (obj) { 410 return obj; 411 }; 412 } 413 if (_browser.supported) { 414 var newVideo = false; 415 navigator.getUserMedia = navigator.getUserMedia || navigator.oGetUserMedia || navigator.msGetUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia; 416 _readyCb = function () { 417 try { 418 if (action === 'stop') { 419 _stop = true; 420 icon.reset(); 421 _stop = false; 422 return; 423 } 424 newVideo = document.createElement('video'); 425 newVideo.width = _w; 426 newVideo.height = _h; 427 navigator.getUserMedia({ 428 video: true, 429 audio: false 430 }, function (stream) { 431 newVideo.src = URL.createObjectURL(stream); 432 newVideo.play(); 433 drawVideo(newVideo); 434 }, function () { 435 }); 436 } catch (e) { 437 throw new Error('Error setting webcam. Message: ' + e.message); 438 } 439 }; 440 if (_ready) { 441 _readyCb(); 442 } 443 } 444 445 }; 446 447 /** 448 * Draw video to context and repeat :) 449 */ 450 function drawVideo(video) { 451 if (video.paused || video.ended || _stop) { 452 return false;
453 } 454 //nasty hack for FF webcam (Thanks to Julian Äwirko, [email protected]) 455 try { 456 _context.clearRect(0, 0, _w, _h); 457 _context.drawImage(video, 0, 0, _w, _h); 458 } catch (e) { 459 460 } 461 _drawTimeout = setTimeout(function () { 462 drawVideo(video); 463 }, animation.duration); 464 link.setIcon(_canvas); 465 } 466 467 var link = {}; 468 /** 469 * Get icon from HEAD tag or create a new <link> element 470 */ 471 link.getIcon = function () { 472 var elm = false; 473 //get link element 474 var getLink = function () { 475 var link = _doc.getElementsByTagName('head')[0].getElementsByTagName('link'); 476 for (var l = link.length, i = (l - 1); i >= 0; i--) { 477 if ((/(^|\s)icon(\s|$)/i).test(link[i].getAttribute('rel'))) { 478 return link[i]; 479 } 480 } 481 return false; 482 }; 483 if (_opt.element) { 484 elm = _opt.element; 485 } else if (_opt.elementId) { 486 //if img element identified by elementId 487 elm = _doc.getElementById(_opt.elementId); 488 elm.setAttribute('href', elm.getAttribute('src')); 489 } else { 490 //if link element 491 elm = getLink(); 492 if (elm === false) { 493 elm = _doc.createElement('link'); 494 elm.setAttribute('rel', 'icon'); 495 _doc.getElementsByTagName('head')[0].appendChild(elm); 496 } 497 } 498 elm.setAttribute('type', 'image/png'); 499 return elm; 500 }; 501 link.setIcon = function (canvas) { 502 var url = canvas.toDataURL('image/png'); 503 if (_opt.dataUrl) { 504 //if using custom exporter 505 _opt.dataUrl(url); 506 } 507 if (_opt.element) { 508 _opt.element.setAttribute('href', url); 509 _opt.element.setAttribute('src', url); 510 } else if (_opt.elementId) { 511 //if is attached to element (image) 512 var elm = _doc.getElementById(_opt.elementId); 513 elm.setAttribute('href', url); 514 elm.setAttribute('src', url); 515 } else { 516 //if is attached to fav icon 517 if (_browser.ff || _browser.opera) { 518 //for FF we need to "recreate" element, atach to dom and remove old <link> 519 //var originalType = _orig.getAttribute('rel'); 520 var old = _orig; 521 _orig = _doc.createElement('link'); 522 //_orig.setAttribute('rel', originalType); 523 if (_browser.opera) { 524 _orig.setAttribute('rel', 'icon'); 525 } 526 _orig.setAttribute('rel', 'icon'); 527 _orig.setAttribute('type', 'image/png'); 528 _doc.getElementsByTagName('head')[0].appendChild(_orig); 529 _orig.setAttribute('href', url); 530 if (old.parentNode) { 531 old.parentNode.removeChild(old); 532 } 533 } else { 534 _orig.setAttribute('href', url); 535 } 536 } 537 }; 538 539 //http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb#answer-5624139 540 //HEX to RGB convertor 541 function hexToRgb(hex) { 542 var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; 543 hex = hex.replace(shorthandRegex, function (m, r, g, b) { 544 return r + r + g + g + b + b; 545 }); 546 var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 547 return result ? { 548 r: parseInt(result[1], 16), 549 g: parseInt(result[2], 16), 550 b: parseInt(result[3], 16) 551 } : false; 552 } 553 554 /** 555 * Merge options 556 */ 557 function merge(def, opt) { 558 var mergedOpt = {}; 559 var attrname; 560 for (attrname in def) { 561 mergedOpt[attrname] = def[attrname]; 562 } 563 for (attrname in opt) { 564 mergedOpt[attrname] = opt[attrname]; 565 } 566 return mergedOpt; 567 } 568 569 /** 570 * Cross-browser page visibility shim 571 * http://stackoverflow.com/questions/12536562/detect-whether-a-window-is-visible 572 */ 573 function isPageHidden() { 574 return _doc.hidden || _doc.msHidden || _doc.webkitHidden || _doc.mozHidden; 575 } 576 577 /** 578 * @namespace animation 579 */ 580 var animation = {}; 581 /** 582 * Animation "frame" duration 583 */ 584 animation.duration = 40; 585 /** 586 * Animation types (none,fade,pop,slide) 587 */ 588 animation.types = {}; 589 animation.types.fade = [{ 590 x: 0.4, 591 y: 0.4, 592 w: 0.6, 593 h: 0.6, 594 o: 0.0 595 }, { 596 x: 0.4, 597 y: 0.4, 598 w: 0.6, 599 h: 0.6, 600 o: 0.1 601 }, { 602 x: 0.4, 603 y: 0.4, 604 w: 0.6, 605 h: 0.6, 606 o: 0.2 607 }, { 608 x: 0.4, 609 y: 0.4, 610 w: 0.6, 611 h: 0.6, 612 o: 0.3 613 }, { 614 x: 0.4, 615 y: 0.4, 616 w: 0.6, 617 h: 0.6, 618 o: 0.4 619 }, { 620 x: 0.4, 621 y: 0.4, 622 w: 0.6, 623 h: 0.6, 624 o: 0.5 625 }, { 626 x: 0.4, 627 y: 0.4, 628 w: 0.6, 629 h: 0.6, 630 o: 0.6 631 }, { 632 x: 0.4, 633 y: 0.4, 634 w: 0.6, 635 h: 0.6, 636 o: 0.7 637 }, { 638 x: 0.4, 639 y: 0.4, 640 w: 0.6, 641 h: 0.6, 642 o: 0.8 643 }, { 644 x: 0.4, 645 y: 0.4, 646 w: 0.6, 647 h: 0.6, 648 o: 0.9 649 }, { 650 x: 0.4, 651 y: 0.4, 652 w: 0.6, 653 h: 0.6, 654 o: 1.0 655 }]; 656 animation.types.none = [{ 657 x: 0.4, 658 y: 0.4, 659 w: 0.6, 660 h: 0.6, 661 o: 1 662 }]; 663 animation.types.pop = [{ 664 x: 1, 665 y: 1, 666 w: 0, 667 h: 0, 668 o: 1 669 }, { 670 x: 0.9, 671 y: 0.9, 672 w: 0.1, 673 h: 0.1, 674 o: 1 675 }, { 676 x: 0.8, 677 y: 0.8, 678 w: 0.2, 679 h: 0.2, 680 o: 1 681 }, { 682 x: 0.7, 683 y: 0.7, 684 w: 0.3, 685 h: 0.3, 686 o: 1 687 }, { 688 x: 0.6, 689 y: 0.6, 690 w: 0.4, 691 h: 0.4, 692 o: 1 693 }, { 694 x: 0.5, 695 y: 0.5, 696 w: 0.5, 697 h: 0.5, 698 o: 1 699 }, { 700 x: 0.4, 701 y: 0.4, 702 w: 0.6, 703 h: 0.6, 704 o: 1 705 }]; 706 animation.types.popFade = [{ 707 x: 0.75, 708 y: 0.75, 709 w: 0, 710 h: 0, 711 o: 0 712 }, { 713 x: 0.65, 714 y: 0.65, 715 w: 0.1, 716 h: 0.1, 717 o: 0.2 718 }, { 719 x: 0.6, 720 y: 0.6, 721 w: 0.2, 722 h: 0.2, 723 o: 0.4 724 }, { 725 x: 0.55, 726 y: 0.55, 727 w: 0.3, 728 h: 0.3, 729 o: 0.6 730 }, { 731 x: 0.50, 732 y: 0.50, 733 w: 0.4, 734 h: 0.4, 735 o: 0.8 736 }, { 737 x: 0.45, 738 y: 0.45, 739 w: 0.5, 740 h: 0.5, 741 o: 0.9 742 }, { 743 x: 0.4, 744 y: 0.4, 745 w: 0.6, 746 h: 0.6, 747 o: 1 748 }]; 749 animation.types.slide = [{ 750 x: 0.4, 751 y: 1, 752 w: 0.6, 753 h: 0.6, 754 o: 1 755 }, { 756 x: 0.4, 757 y: 0.9, 758 w: 0.6, 759 h: 0.6, 760 o: 1 761 }, { 762 x: 0.4, 763 y: 0.9, 764 w: 0.6, 765 h: 0.6, 766 o: 1 767 }, { 768 x: 0.4, 769 y: 0.8, 770 w: 0.6, 771 h: 0.6, 772 o: 1 773 }, { 774 x: 0.4, 775 y: 0.7, 776 w: 0.6, 777 h: 0.6, 778 o: 1 779 }, { 780 x: 0.4, 781 y: 0.6, 782 w: 0.6, 783 h: 0.6, 784 o: 1 785 }, { 786 x: 0.4, 787 y: 0.5, 788 w: 0.6, 789 h: 0.6, 790 o: 1 791 }, { 792 x: 0.4, 793 y: 0.4, 794 w: 0.6, 795 h: 0.6, 796 o: 1 797 }]; 798 /** 799 * Run animation 800 * @param {Object} opt Animation options 801 * @param {Object} cb Callabak after all steps are done 802 * @param {Object} revert Reverse order? true|false 803 * @param {Object} step Optional step number (frame bumber) 804 */ 805 animation.run = function (opt, cb, revert, step) { 806 var animationType = animation.types[isPageHidden() ? 'none' : _opt.animation]; 807 if (revert === true) { 808 step = (typeof step !== 'undefined') ? step : animationType.length - 1; 809 } else { 810 step = (typeof step !== 'undefined') ? step : 0; 811 } 812 cb = (cb) ? cb : function () { 813 }; 814 if ((step < animationType.length) && (step >= 0)) { 815 type[_opt.type](merge(opt, animationType[step])); 816 _animTimeout = setTimeout(function () { 817 if (revert) { 818 step = step - 1; 819 } else { 820 step = step + 1; 821 } 822 animation.run(opt, cb, revert, step); 823 }, animation.duration); 824 825 link.setIcon(_canvas); 826 } else { 827 cb(); 828 return; 829 } 830 }; 831 //auto init 832 init(); 833 return { 834 badge: badge, 835 video: video, 836 image: image, 837 webcam: webcam, 838 reset: icon.reset, 839 browser: { 840 supported: _browser.supported 841 } 842 }; 843 }); 844 845 // AMD / RequireJS 846 if (typeof define !== 'undefined' && define.amd) { 847 define([], function () { 848 return Favico; 849 }); 850 } 851 // CommonJS 852 else if (typeof module !== 'undefined' && module.exports) { 853 module.exports = Favico; 854 } 855 // included directly via <script> tag 856 else { 857 this.Favico = Favico; 858 } 859 860})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.