github.com/fanux/shipyard@v0.0.0-20161009071005-6515ce223235/controller/static/semantic/dist/components/popup.js (about) 1 /*! 2 * # Semantic UI x.x - Popup 3 * http://github.com/semantic-org/semantic-ui/ 4 * 5 * 6 * Copyright 2014 Contributors 7 * Released under the MIT license 8 * http://opensource.org/licenses/MIT 9 * 10 */ 11 12 ;(function ($, window, document, undefined) { 13 14 "use strict"; 15 16 $.fn.popup = function(parameters) { 17 var 18 $allModules = $(this), 19 $document = $(document), 20 21 moduleSelector = $allModules.selector || '', 22 23 hasTouch = ('ontouchstart' in document.documentElement), 24 time = new Date().getTime(), 25 performance = [], 26 27 query = arguments[0], 28 methodInvoked = (typeof query == 'string'), 29 queryArguments = [].slice.call(arguments, 1), 30 31 returnedValue 32 ; 33 $allModules 34 .each(function() { 35 var 36 settings = ( $.isPlainObject(parameters) ) 37 ? $.extend(true, {}, $.fn.popup.settings, parameters) 38 : $.extend({}, $.fn.popup.settings), 39 40 selector = settings.selector, 41 className = settings.className, 42 error = settings.error, 43 metadata = settings.metadata, 44 namespace = settings.namespace, 45 46 eventNamespace = '.' + settings.namespace, 47 moduleNamespace = 'module-' + namespace, 48 49 $module = $(this), 50 $context = $(settings.context), 51 $target = (settings.target) 52 ? $(settings.target) 53 : $module, 54 55 $window = $(window), 56 $body = $('body'), 57 $popup, 58 $offsetParent, 59 60 searchDepth = 0, 61 triedPositions = false, 62 63 element = this, 64 instance = $module.data(moduleNamespace), 65 66 elementNamespace, 67 id, 68 module 69 ; 70 71 module = { 72 73 // binds events 74 initialize: function() { 75 module.debug('Initializing', $module); 76 module.createID(); 77 module.bind.events(); 78 if( !module.exists() && settings.preserve) { 79 module.create(); 80 } 81 module.instantiate(); 82 }, 83 84 instantiate: function() { 85 module.verbose('Storing instance', module); 86 instance = module; 87 $module 88 .data(moduleNamespace, instance) 89 ; 90 }, 91 92 refresh: function() { 93 if(settings.popup) { 94 $popup = $(settings.popup).eq(0); 95 } 96 else { 97 if(settings.inline) { 98 $popup = $target.next(selector.popup).eq(0); 99 } 100 } 101 if(settings.popup) { 102 $popup.addClass(className.loading); 103 $offsetParent = module.get.offsetParent(); 104 $popup.removeClass(className.loading); 105 if(settings.movePopup && module.has.popup() && module.get.offsetParent($popup)[0] !== $offsetParent[0]) { 106 module.debug('Moving popup to the same offset parent as activating element'); 107 $popup 108 .detach() 109 .appendTo($offsetParent) 110 ; 111 } 112 } 113 else { 114 $offsetParent = (settings.inline) 115 ? module.get.offsetParent($target) 116 : module.has.popup() 117 ? module.get.offsetParent($popup) 118 : $body 119 ; 120 } 121 if( $offsetParent.is('html') ) { 122 module.debug('Setting page as offset parent'); 123 $offsetParent = $body; 124 } 125 }, 126 127 reposition: function() { 128 module.refresh(); 129 module.set.position(); 130 }, 131 132 destroy: function() { 133 module.debug('Destroying previous module'); 134 // remove element only if was created dynamically 135 if($popup && !settings.preserve) { 136 module.removePopup(); 137 } 138 // clear all timeouts 139 clearTimeout(module.hideTimer); 140 clearTimeout(module.showTimer); 141 // remove events 142 $window.off(elementNamespace); 143 $module 144 .off(eventNamespace) 145 .removeData(moduleNamespace) 146 ; 147 }, 148 149 event: { 150 start: function(event) { 151 var 152 delay = ($.isPlainObject(settings.delay)) 153 ? settings.delay.show 154 : settings.delay 155 ; 156 clearTimeout(module.hideTimer); 157 module.showTimer = setTimeout(function() { 158 if(module.is.hidden() && !( module.is.active() && module.is.dropdown()) ) { 159 module.show(); 160 } 161 }, delay); 162 }, 163 end: function() { 164 var 165 delay = ($.isPlainObject(settings.delay)) 166 ? settings.delay.hide 167 : settings.delay 168 ; 169 clearTimeout(module.showTimer); 170 module.hideTimer = setTimeout(function() { 171 if(module.is.visible() ) { 172 module.hide(); 173 } 174 }, delay); 175 }, 176 resize: function() { 177 if( module.is.visible() ) { 178 module.set.position(); 179 } 180 } 181 }, 182 183 // generates popup html from metadata 184 create: function() { 185 var 186 html = $module.data(metadata.html) || settings.html, 187 variation = $module.data(metadata.variation) || settings.variation, 188 title = $module.data(metadata.title) || settings.title, 189 content = $module.data(metadata.content) || $module.attr('title') || settings.content 190 ; 191 if(html || content || title) { 192 module.debug('Creating pop-up html'); 193 if(!html) { 194 html = settings.templates.popup({ 195 title : title, 196 content : content 197 }); 198 } 199 $popup = $('<div/>') 200 .addClass(className.popup) 201 .addClass(variation) 202 .data(metadata.activator, $module) 203 .html(html) 204 ; 205 if(variation) { 206 $popup 207 .addClass(variation) 208 ; 209 } 210 if(settings.inline) { 211 module.verbose('Inserting popup element inline', $popup); 212 $popup 213 .insertAfter($module) 214 ; 215 } 216 else { 217 module.verbose('Appending popup element to body', $popup); 218 $popup 219 .appendTo( $context ) 220 ; 221 } 222 module.refresh(); 223 if(settings.hoverable) { 224 module.bind.popup(); 225 } 226 settings.onCreate.call($popup, element); 227 } 228 else if($target.next(selector.popup).length !== 0) { 229 module.verbose('Pre-existing popup found'); 230 settings.inline = true; 231 settings.popup = $target.next(selector.popup).data(metadata.activator, $module); 232 module.refresh(); 233 if(settings.hoverable) { 234 module.bind.popup(); 235 } 236 } 237 else if(settings.popup) { 238 settings.popup.data(metadata.activator, $module); 239 module.verbose('Used popup specified in settings'); 240 module.refresh(); 241 if(settings.hoverable) { 242 module.bind.popup(); 243 } 244 } 245 else { 246 module.debug('No content specified skipping display', element); 247 } 248 }, 249 250 createID: function() { 251 id = (Math.random().toString(16) + '000000000').substr(2,8); 252 elementNamespace = '.' + id; 253 module.verbose('Creating unique id for element', id); 254 }, 255 256 // determines popup state 257 toggle: function() { 258 module.debug('Toggling pop-up'); 259 if( module.is.hidden() ) { 260 module.debug('Popup is hidden, showing pop-up'); 261 module.unbind.close(); 262 module.show(); 263 } 264 else { 265 module.debug('Popup is visible, hiding pop-up'); 266 module.hide(); 267 } 268 }, 269 270 show: function(callback) { 271 callback = $.isFunction(callback) ? callback : function(){}; 272 module.debug('Showing pop-up', settings.transition); 273 if( !module.exists() ) { 274 module.create(); 275 } 276 else if(!settings.preserve && !settings.popup) { 277 module.refresh(); 278 } 279 if( $popup && module.set.position() ) { 280 module.save.conditions(); 281 if(settings.exclusive) { 282 module.hideAll(); 283 } 284 module.animate.show(callback); 285 } 286 }, 287 288 289 hide: function(callback) { 290 callback = $.isFunction(callback) ? callback : function(){}; 291 module.remove.visible(); 292 module.unbind.close(); 293 if( module.is.visible() ) { 294 module.restore.conditions(); 295 module.animate.hide(callback); 296 } 297 }, 298 299 hideAll: function() { 300 $(selector.popup) 301 .filter('.' + className.visible) 302 .each(function() { 303 $(this) 304 .data(metadata.activator) 305 .popup('hide') 306 ; 307 }) 308 ; 309 }, 310 311 hideGracefully: function(event) { 312 // don't close on clicks inside popup 313 if(event && $(event.target).closest(selector.popup).length === 0) { 314 module.debug('Click occurred outside popup hiding popup'); 315 module.hide(); 316 } 317 else { 318 module.debug('Click was inside popup, keeping popup open'); 319 } 320 }, 321 322 exists: function() { 323 if(!$popup) { 324 return false; 325 } 326 if(settings.inline || settings.popup) { 327 return ( module.has.popup() ); 328 } 329 else { 330 return ( $popup.closest($context).length >= 1 ) 331 ? true 332 : false 333 ; 334 } 335 }, 336 337 removePopup: function() { 338 module.debug('Removing popup', $popup); 339 if( module.has.popup() && !settings.popup) { 340 $popup.remove(); 341 $popup = undefined; 342 } 343 settings.onRemove.call($popup, element); 344 }, 345 346 save: { 347 conditions: function() { 348 module.cache = { 349 title: $module.attr('title') 350 }; 351 if (module.cache.title) { 352 $module.removeAttr('title'); 353 } 354 module.verbose('Saving original attributes', module.cache.title); 355 } 356 }, 357 restore: { 358 conditions: function() { 359 if(module.cache && module.cache.title) { 360 $module.attr('title', module.cache.title); 361 module.verbose('Restoring original attributes', module.cache.title); 362 } 363 return true; 364 } 365 }, 366 animate: { 367 show: function(callback) { 368 callback = $.isFunction(callback) ? callback : function(){}; 369 if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) { 370 module.set.visible(); 371 $popup 372 .transition({ 373 animation : settings.transition + ' in', 374 queue : false, 375 debug : settings.debug, 376 verbose : settings.verbose, 377 duration : settings.duration, 378 onComplete : function() { 379 module.bind.close(); 380 callback.call($popup, element); 381 settings.onVisible.call($popup, element); 382 } 383 }) 384 ; 385 } 386 else { 387 module.set.visible(); 388 $popup 389 .stop() 390 .fadeIn(settings.duration, settings.easing, function() { 391 module.bind.close(); 392 callback.call($popup, element); 393 settings.onVisible.call($popup, element); 394 }) 395 ; 396 } 397 settings.onShow.call($popup, element); 398 }, 399 hide: function(callback) { 400 callback = $.isFunction(callback) ? callback : function(){}; 401 module.debug('Hiding pop-up'); 402 if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) { 403 $popup 404 .transition({ 405 animation : settings.transition + ' out', 406 queue : false, 407 duration : settings.duration, 408 debug : settings.debug, 409 verbose : settings.verbose, 410 onComplete : function() { 411 module.reset(); 412 callback.call($popup, element); 413 settings.onHidden.call($popup, element); 414 } 415 }) 416 ; 417 } 418 else { 419 $popup 420 .stop() 421 .fadeOut(settings.duration, settings.easing, function() { 422 module.reset(); 423 callback.call($popup, element); 424 settings.onHidden.call($popup, element); 425 }) 426 ; 427 } 428 settings.onHide.call($popup, element); 429 } 430 }, 431 432 get: { 433 id: function() { 434 return id; 435 }, 436 startEvent: function() { 437 if(settings.on == 'hover') { 438 return (hasTouch) 439 ? 'touchstart mouseenter' 440 : 'mouseenter' 441 ; 442 } 443 else if(settings.on == 'focus') { 444 return 'focus'; 445 } 446 return false; 447 }, 448 scrollEvent: function() { 449 return (hasTouch) 450 ? 'touchmove scroll' 451 : 'scroll' 452 ; 453 }, 454 endEvent: function() { 455 if(settings.on == 'hover') { 456 return 'mouseleave'; 457 } 458 else if(settings.on == 'focus') { 459 return 'blur'; 460 } 461 return false; 462 }, 463 offsetParent: function($target) { 464 var 465 element = ($target !== undefined) 466 ? $target[0] 467 : $module[0], 468 parentNode = element.parentNode, 469 $node = $(parentNode) 470 ; 471 if(parentNode) { 472 var 473 is2D = ($node.css('transform') === 'none'), 474 isStatic = ($node.css('position') === 'static'), 475 isHTML = $node.is('html') 476 ; 477 while(parentNode && !isHTML && isStatic && is2D) { 478 parentNode = parentNode.parentNode; 479 $node = $(parentNode); 480 is2D = ($node.css('transform') === 'none'); 481 isStatic = ($node.css('position') === 'static'); 482 isHTML = $node.is('html'); 483 } 484 } 485 return ($node && $node.length > 0) 486 ? $node 487 : $() 488 ; 489 }, 490 offstagePosition: function(position) { 491 var 492 boundary = { 493 top : $(window).scrollTop(), 494 bottom : $(window).scrollTop() + $(window).height(), 495 left : 0, 496 right : $(window).width() 497 }, 498 popup = { 499 width : $popup.width(), 500 height : $popup.height(), 501 offset : $popup.offset() 502 }, 503 offstage = {}, 504 offstagePositions = [] 505 ; 506 position = position || false; 507 if(popup.offset && position) { 508 module.verbose('Checking if outside viewable area', popup.offset); 509 offstage = { 510 top : (popup.offset.top < boundary.top), 511 bottom : (popup.offset.top + popup.height > boundary.bottom), 512 right : (popup.offset.left + popup.width > boundary.right), 513 left : (popup.offset.left < boundary.left) 514 }; 515 } 516 // return only boundaries that have been surpassed 517 $.each(offstage, function(direction, isOffstage) { 518 if(isOffstage) { 519 offstagePositions.push(direction); 520 } 521 }); 522 return (offstagePositions.length > 0) 523 ? offstagePositions.join(' ') 524 : false 525 ; 526 }, 527 positions: function() { 528 return { 529 'top left' : false, 530 'top center' : false, 531 'top right' : false, 532 'bottom left' : false, 533 'bottom center' : false, 534 'bottom right' : false, 535 'left center' : false, 536 'right center' : false 537 }; 538 }, 539 nextPosition: function(position) { 540 var 541 positions = position.split(' '), 542 verticalPosition = positions[0], 543 horizontalPosition = positions[1], 544 opposite = { 545 top : 'bottom', 546 bottom : 'top', 547 left : 'right', 548 right : 'left' 549 }, 550 adjacent = { 551 left : 'center', 552 center : 'right', 553 right : 'left' 554 }, 555 backup = { 556 'top left' : 'top center', 557 'top center' : 'top right', 558 'top right' : 'right center', 559 'right center' : 'bottom right', 560 'bottom right' : 'bottom center', 561 'bottom center' : 'bottom left', 562 'bottom left' : 'left center', 563 'left center' : 'top left' 564 }, 565 adjacentsAvailable = (verticalPosition == 'top' || verticalPosition == 'bottom'), 566 oppositeTried = false, 567 adjacentTried = false, 568 nextPosition = false 569 ; 570 if(!triedPositions) { 571 module.verbose('All available positions available'); 572 triedPositions = module.get.positions(); 573 } 574 575 module.debug('Recording last position tried', position); 576 triedPositions[position] = true; 577 578 if(settings.prefer === 'opposite') { 579 nextPosition = [opposite[verticalPosition], horizontalPosition]; 580 nextPosition = nextPosition.join(' '); 581 oppositeTried = (triedPositions[nextPosition] === true); 582 module.debug('Trying opposite strategy', nextPosition); 583 } 584 if((settings.prefer === 'adjacent') && adjacentsAvailable ) { 585 nextPosition = [verticalPosition, adjacent[horizontalPosition]]; 586 nextPosition = nextPosition.join(' '); 587 adjacentTried = (triedPositions[nextPosition] === true); 588 module.debug('Trying adjacent strategy', nextPosition); 589 } 590 if(adjacentTried || oppositeTried) { 591 module.debug('Using backup position', nextPosition); 592 nextPosition = backup[position]; 593 } 594 return nextPosition; 595 } 596 }, 597 598 set: { 599 position: function(position, arrowOffset) { 600 var 601 windowWidth = $(window).width(), 602 windowHeight = $(window).height(), 603 604 targetWidth = $target.outerWidth(), 605 targetHeight = $target.outerHeight(), 606 607 popupWidth = $popup.outerWidth(), 608 popupHeight = $popup.outerHeight(), 609 610 parentWidth = $offsetParent.outerWidth(), 611 parentHeight = $offsetParent.outerHeight(), 612 613 distanceAway = settings.distanceAway, 614 615 targetElement = $target[0], 616 617 marginTop = (settings.inline) 618 ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10) 619 : 0, 620 marginLeft = (settings.inline) 621 ? parseInt( window.getComputedStyle(targetElement).getPropertyValue(module.is.rtl() ? 'margin-right' : 'margin-left'), 10) 622 : 0, 623 624 target = (settings.inline || settings.popup) 625 ? $target.position() 626 : $target.offset(), 627 628 computedPosition, 629 positioning, 630 offstagePosition 631 ; 632 position = position || $module.data(metadata.position) || settings.position; 633 arrowOffset = arrowOffset || $module.data(metadata.offset) || settings.offset; 634 635 if(searchDepth == settings.maxSearchDepth && settings.lastResort) { 636 module.debug('Using last resort position to display', settings.lastResort); 637 position = settings.lastResort; 638 } 639 640 if(settings.inline) { 641 module.debug('Adding targets margin to calculation'); 642 if(position == 'left center' || position == 'right center') { 643 arrowOffset += marginTop; 644 distanceAway += -marginLeft; 645 } 646 else if (position == 'top left' || position == 'top center' || position == 'top right') { 647 arrowOffset += marginLeft; 648 distanceAway -= marginTop; 649 } 650 else { 651 arrowOffset += marginLeft; 652 distanceAway += marginTop; 653 } 654 } 655 module.debug('Calculating popup positioning', position); 656 657 computedPosition = position; 658 if (module.is.rtl()) { 659 computedPosition = computedPosition.replace(/left|right/g, function (match) { 660 return (match == 'left') 661 ? 'right' 662 : 'left' 663 ; 664 }); 665 module.debug('RTL: Popup positioning updated', computedPosition); 666 } 667 switch (computedPosition) { 668 case 'top left': 669 positioning = { 670 top : 'auto', 671 bottom : parentHeight - target.top + distanceAway, 672 left : target.left + arrowOffset, 673 right : 'auto' 674 }; 675 break; 676 case 'top center': 677 positioning = { 678 bottom : parentHeight - target.top + distanceAway, 679 left : target.left + (targetWidth / 2) - (popupWidth / 2) + arrowOffset, 680 top : 'auto', 681 right : 'auto' 682 }; 683 break; 684 case 'top right': 685 positioning = { 686 bottom : parentHeight - target.top + distanceAway, 687 right : parentWidth - target.left - targetWidth - arrowOffset, 688 top : 'auto', 689 left : 'auto' 690 }; 691 break; 692 case 'left center': 693 positioning = { 694 top : target.top + (targetHeight / 2) - (popupHeight / 2) + arrowOffset, 695 right : parentWidth - target.left + distanceAway, 696 left : 'auto', 697 bottom : 'auto' 698 }; 699 break; 700 case 'right center': 701 positioning = { 702 top : target.top + (targetHeight / 2) - (popupHeight / 2) + arrowOffset, 703 left : target.left + targetWidth + distanceAway, 704 bottom : 'auto', 705 right : 'auto' 706 }; 707 break; 708 case 'bottom left': 709 positioning = { 710 top : target.top + targetHeight + distanceAway, 711 left : target.left + arrowOffset, 712 bottom : 'auto', 713 right : 'auto' 714 }; 715 break; 716 case 'bottom center': 717 positioning = { 718 top : target.top + targetHeight + distanceAway, 719 left : target.left + (targetWidth / 2) - (popupWidth / 2) + arrowOffset, 720 bottom : 'auto', 721 right : 'auto' 722 }; 723 break; 724 case 'bottom right': 725 positioning = { 726 top : target.top + targetHeight + distanceAway, 727 right : parentWidth - target.left - targetWidth - arrowOffset, 728 left : 'auto', 729 bottom : 'auto' 730 }; 731 break; 732 } 733 if(positioning === undefined) { 734 module.error(error.invalidPosition, position); 735 } 736 737 module.debug('Calculated popup positioning values', positioning); 738 739 // tentatively place on stage 740 $popup 741 .css(positioning) 742 .removeClass(className.position) 743 .addClass(position) 744 .addClass(className.loading) 745 ; 746 // check if is offstage 747 offstagePosition = module.get.offstagePosition(position); 748 749 // recursively find new positioning 750 if(offstagePosition) { 751 module.debug('Popup cant fit into viewport', offstagePosition); 752 if(searchDepth < settings.maxSearchDepth) { 753 searchDepth++; 754 position = module.get.nextPosition(position); 755 module.debug('Trying new position', position); 756 return ($popup) 757 ? module.set.position(position) 758 : false 759 ; 760 } 761 else if(!settings.lastResort) { 762 module.debug('Popup could not find a position in view', $popup); 763 module.error(error.cannotPlace, element); 764 module.remove.attempts(); 765 module.remove.loading(); 766 module.reset(); 767 return false; 768 } 769 } 770 771 module.debug('Position is on stage', position); 772 module.remove.attempts(); 773 module.set.fluidWidth(); 774 module.remove.loading(); 775 return true; 776 }, 777 778 fluidWidth: function() { 779 if( settings.setFluidWidth && $popup.hasClass(className.fluid) ) { 780 $popup.css('width', $offsetParent.width()); 781 } 782 }, 783 784 visible: function() { 785 $module.addClass(className.visible); 786 } 787 }, 788 789 remove: { 790 loading: function() { 791 $popup.removeClass(className.loading); 792 }, 793 visible: function() { 794 $module.removeClass(className.visible); 795 }, 796 attempts: function() { 797 module.verbose('Resetting all searched positions'); 798 searchDepth = 0; 799 triedPositions = false; 800 } 801 }, 802 803 bind: { 804 events: function() { 805 module.debug('Binding popup events to module'); 806 if(settings.on == 'click') { 807 $module 808 .on('click' + eventNamespace, module.toggle) 809 ; 810 } 811 else if( module.get.startEvent() ) { 812 $module 813 .on(module.get.startEvent() + eventNamespace, module.event.start) 814 .on(module.get.endEvent() + eventNamespace, module.event.end) 815 ; 816 } 817 if(settings.target) { 818 module.debug('Target set to element', $target); 819 } 820 $window.on('resize' + elementNamespace, module.event.resize); 821 }, 822 popup: function() { 823 module.verbose('Allowing hover events on popup to prevent closing'); 824 if( $popup && module.has.popup() ) { 825 $popup 826 .on('mouseenter' + eventNamespace, module.event.start) 827 .on('mouseleave' + eventNamespace, module.event.end) 828 ; 829 } 830 }, 831 close:function() { 832 if(settings.hideOnScroll === true || settings.hideOnScroll == 'auto' && settings.on != 'click') { 833 $document 834 .one(module.get.scrollEvent() + elementNamespace, module.hideGracefully) 835 ; 836 $context 837 .one(module.get.scrollEvent() + elementNamespace, module.hideGracefully) 838 ; 839 } 840 if(settings.on == 'click' && settings.closable) { 841 module.verbose('Binding popup close event to document'); 842 $document 843 .on('click' + elementNamespace, function(event) { 844 module.verbose('Pop-up clickaway intent detected'); 845 module.hideGracefully.call(element, event); 846 }) 847 ; 848 } 849 } 850 }, 851 852 unbind: { 853 close: function() { 854 if(settings.hideOnScroll === true || settings.hideOnScroll == 'auto' && settings.on != 'click') { 855 $document 856 .off('scroll' + elementNamespace, module.hide) 857 ; 858 $context 859 .off('scroll' + elementNamespace, module.hide) 860 ; 861 } 862 if(settings.on == 'click' && settings.closable) { 863 module.verbose('Removing close event from document'); 864 $document 865 .off('click' + elementNamespace) 866 ; 867 } 868 } 869 }, 870 871 has: { 872 popup: function() { 873 return ($popup && $popup.length > 0); 874 } 875 }, 876 877 is: { 878 active: function() { 879 return $module.hasClass(className.active); 880 }, 881 animating: function() { 882 return ( $popup && $popup.is(':animated') || $popup.hasClass(className.animating) ); 883 }, 884 visible: function() { 885 return $popup && $popup.is(':visible'); 886 }, 887 dropdown: function() { 888 return $module.hasClass(className.dropdown); 889 }, 890 hidden: function() { 891 return !module.is.visible(); 892 }, 893 rtl: function () { 894 return $module.css('direction') == 'rtl'; 895 } 896 }, 897 898 reset: function() { 899 module.remove.visible(); 900 if(settings.preserve) { 901 if($.fn.transition !== undefined) { 902 $popup 903 .transition('remove transition') 904 ; 905 } 906 } 907 else { 908 module.removePopup(); 909 } 910 }, 911 912 setting: function(name, value) { 913 if( $.isPlainObject(name) ) { 914 $.extend(true, settings, name); 915 } 916 else if(value !== undefined) { 917 settings[name] = value; 918 } 919 else { 920 return settings[name]; 921 } 922 }, 923 internal: function(name, value) { 924 if( $.isPlainObject(name) ) { 925 $.extend(true, module, name); 926 } 927 else if(value !== undefined) { 928 module[name] = value; 929 } 930 else { 931 return module[name]; 932 } 933 }, 934 debug: function() { 935 if(settings.debug) { 936 if(settings.performance) { 937 module.performance.log(arguments); 938 } 939 else { 940 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); 941 module.debug.apply(console, arguments); 942 } 943 } 944 }, 945 verbose: function() { 946 if(settings.verbose && settings.debug) { 947 if(settings.performance) { 948 module.performance.log(arguments); 949 } 950 else { 951 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); 952 module.verbose.apply(console, arguments); 953 } 954 } 955 }, 956 error: function() { 957 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); 958 module.error.apply(console, arguments); 959 }, 960 performance: { 961 log: function(message) { 962 var 963 currentTime, 964 executionTime, 965 previousTime 966 ; 967 if(settings.performance) { 968 currentTime = new Date().getTime(); 969 previousTime = time || currentTime; 970 executionTime = currentTime - previousTime; 971 time = currentTime; 972 performance.push({ 973 'Name' : message[0], 974 'Arguments' : [].slice.call(message, 1) || '', 975 'Element' : element, 976 'Execution Time' : executionTime 977 }); 978 } 979 clearTimeout(module.performance.timer); 980 module.performance.timer = setTimeout(module.performance.display, 100); 981 }, 982 display: function() { 983 var 984 title = settings.name + ':', 985 totalTime = 0 986 ; 987 time = false; 988 clearTimeout(module.performance.timer); 989 $.each(performance, function(index, data) { 990 totalTime += data['Execution Time']; 991 }); 992 title += ' ' + totalTime + 'ms'; 993 if(moduleSelector) { 994 title += ' \'' + moduleSelector + '\''; 995 } 996 if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { 997 console.groupCollapsed(title); 998 if(console.table) { 999 console.table(performance); 1000 } 1001 else { 1002 $.each(performance, function(index, data) { 1003 console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); 1004 }); 1005 } 1006 console.groupEnd(); 1007 } 1008 performance = []; 1009 } 1010 }, 1011 invoke: function(query, passedArguments, context) { 1012 var 1013 object = instance, 1014 maxDepth, 1015 found, 1016 response 1017 ; 1018 passedArguments = passedArguments || queryArguments; 1019 context = element || context; 1020 if(typeof query == 'string' && object !== undefined) { 1021 query = query.split(/[\. ]/); 1022 maxDepth = query.length - 1; 1023 $.each(query, function(depth, value) { 1024 var camelCaseValue = (depth != maxDepth) 1025 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) 1026 : query 1027 ; 1028 if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { 1029 object = object[camelCaseValue]; 1030 } 1031 else if( object[camelCaseValue] !== undefined ) { 1032 found = object[camelCaseValue]; 1033 return false; 1034 } 1035 else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { 1036 object = object[value]; 1037 } 1038 else if( object[value] !== undefined ) { 1039 found = object[value]; 1040 return false; 1041 } 1042 else { 1043 return false; 1044 } 1045 }); 1046 } 1047 if ( $.isFunction( found ) ) { 1048 response = found.apply(context, passedArguments); 1049 } 1050 else if(found !== undefined) { 1051 response = found; 1052 } 1053 if($.isArray(returnedValue)) { 1054 returnedValue.push(response); 1055 } 1056 else if(returnedValue !== undefined) { 1057 returnedValue = [returnedValue, response]; 1058 } 1059 else if(response !== undefined) { 1060 returnedValue = response; 1061 } 1062 return found; 1063 } 1064 }; 1065 1066 if(methodInvoked) { 1067 if(instance === undefined) { 1068 module.initialize(); 1069 } 1070 module.invoke(query); 1071 } 1072 else { 1073 if(instance !== undefined) { 1074 instance.invoke('destroy'); 1075 } 1076 module.initialize(); 1077 } 1078 }) 1079 ; 1080 1081 return (returnedValue !== undefined) 1082 ? returnedValue 1083 : this 1084 ; 1085 }; 1086 1087 $.fn.popup.settings = { 1088 1089 name : 'Popup', 1090 1091 debug : false, 1092 verbose : true, 1093 performance : true, 1094 namespace : 'popup', 1095 1096 onCreate : function(){}, 1097 onRemove : function(){}, 1098 1099 onShow : function(){}, 1100 onVisible : function(){}, 1101 onHide : function(){}, 1102 onHidden : function(){}, 1103 1104 variation : '', 1105 content : false, 1106 html : false, 1107 title : false, 1108 1109 on : 'hover', 1110 closable : true, 1111 hideOnScroll : 'auto', 1112 exclusive : true, 1113 1114 context : 'body', 1115 1116 position : 'top left', 1117 prefer : 'opposite', 1118 lastResort : false, 1119 1120 delay : { 1121 show : 30, 1122 hide : 0 1123 }, 1124 1125 setFluidWidth : true, 1126 movePopup : true, 1127 1128 target : false, 1129 popup : false, 1130 inline : false, 1131 preserve : false, 1132 hoverable : false, 1133 1134 duration : 200, 1135 easing : 'easeOutQuint', 1136 transition : 'scale', 1137 1138 distanceAway : 0, 1139 offset : 0, 1140 maxSearchDepth : 20, 1141 1142 error: { 1143 invalidPosition : 'The position you specified is not a valid position', 1144 cannotPlace : 'No visible position could be found for the popup', 1145 method : 'The method you called is not defined.' 1146 }, 1147 1148 metadata: { 1149 activator : 'activator', 1150 content : 'content', 1151 html : 'html', 1152 offset : 'offset', 1153 position : 'position', 1154 title : 'title', 1155 variation : 'variation' 1156 }, 1157 1158 className : { 1159 active : 'active', 1160 animating : 'animating', 1161 dropdown : 'dropdown', 1162 fluid : 'fluid', 1163 loading : 'loading', 1164 popup : 'ui popup', 1165 position : 'top left center bottom right', 1166 visible : 'visible' 1167 }, 1168 1169 selector : { 1170 popup : '.ui.popup' 1171 }, 1172 1173 templates: { 1174 escape: function(string) { 1175 var 1176 badChars = /[&<>"'`]/g, 1177 shouldEscape = /[&<>"'`]/, 1178 escape = { 1179 "&": "&", 1180 "<": "<", 1181 ">": ">", 1182 '"': """, 1183 "'": "'", 1184 "`": "`" 1185 }, 1186 escapedChar = function(chr) { 1187 return escape[chr]; 1188 } 1189 ; 1190 if(shouldEscape.test(string)) { 1191 return string.replace(badChars, escapedChar); 1192 } 1193 return string; 1194 }, 1195 popup: function(text) { 1196 var 1197 html = '', 1198 escape = $.fn.popup.settings.templates.escape 1199 ; 1200 if(typeof text !== undefined) { 1201 if(typeof text.title !== undefined && text.title) { 1202 text.title = escape(text.title); 1203 html += '<div class="header">' + text.title + '</div>'; 1204 } 1205 if(typeof text.content !== undefined && text.content) { 1206 text.content = escape(text.content); 1207 html += '<div class="content">' + text.content + '</div>'; 1208 } 1209 } 1210 return html; 1211 } 1212 } 1213 1214 }; 1215 1216 // Adds easing 1217 $.extend( $.easing, { 1218 easeOutQuad: function (x, t, b, c, d) { 1219 return -c *(t/=d)*(t-2) + b; 1220 } 1221 }); 1222 1223 1224 })( jQuery, window , document );