| Conditions | 5 |
| Paths | 0 |
| Total Lines | 1476 |
| Code Lines | 975 |
| Lines | 1476 |
| Ratio | 100 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | /*! |
||
| 11 | View Code Duplication | ;(function ($, window, document, undefined) { |
|
|
|
|||
| 12 | |||
| 13 | "use strict"; |
||
| 14 | |||
| 15 | window = (typeof window != 'undefined' && window.Math == Math) |
||
| 16 | ? window |
||
| 17 | : (typeof self != 'undefined' && self.Math == Math) |
||
| 18 | ? self |
||
| 19 | : Function('return this')() |
||
| 20 | ; |
||
| 21 | |||
| 22 | $.fn.popup = function(parameters) { |
||
| 23 | var |
||
| 24 | $allModules = $(this), |
||
| 25 | $document = $(document), |
||
| 26 | $window = $(window), |
||
| 27 | $body = $('body'), |
||
| 28 | |||
| 29 | moduleSelector = $allModules.selector || '', |
||
| 30 | |||
| 31 | hasTouch = (true), |
||
| 32 | time = new Date().getTime(), |
||
| 33 | performance = [], |
||
| 34 | |||
| 35 | query = arguments[0], |
||
| 36 | methodInvoked = (typeof query == 'string'), |
||
| 37 | queryArguments = [].slice.call(arguments, 1), |
||
| 38 | |||
| 39 | returnedValue |
||
| 40 | ; |
||
| 41 | $allModules |
||
| 42 | .each(function() { |
||
| 43 | var |
||
| 44 | settings = ( $.isPlainObject(parameters) ) |
||
| 45 | ? $.extend(true, {}, $.fn.popup.settings, parameters) |
||
| 46 | : $.extend({}, $.fn.popup.settings), |
||
| 47 | |||
| 48 | selector = settings.selector, |
||
| 49 | className = settings.className, |
||
| 50 | error = settings.error, |
||
| 51 | metadata = settings.metadata, |
||
| 52 | namespace = settings.namespace, |
||
| 53 | |||
| 54 | eventNamespace = '.' + settings.namespace, |
||
| 55 | moduleNamespace = 'module-' + namespace, |
||
| 56 | |||
| 57 | $module = $(this), |
||
| 58 | $context = $(settings.context), |
||
| 59 | $scrollContext = $(settings.scrollContext), |
||
| 60 | $boundary = $(settings.boundary), |
||
| 61 | $target = (settings.target) |
||
| 62 | ? $(settings.target) |
||
| 63 | : $module, |
||
| 64 | |||
| 65 | $popup, |
||
| 66 | $offsetParent, |
||
| 67 | |||
| 68 | searchDepth = 0, |
||
| 69 | triedPositions = false, |
||
| 70 | openedWithTouch = false, |
||
| 71 | |||
| 72 | element = this, |
||
| 73 | instance = $module.data(moduleNamespace), |
||
| 74 | |||
| 75 | documentObserver, |
||
| 76 | elementNamespace, |
||
| 77 | id, |
||
| 78 | module |
||
| 79 | ; |
||
| 80 | |||
| 81 | module = { |
||
| 82 | |||
| 83 | // binds events |
||
| 84 | initialize: function() { |
||
| 85 | module.debug('Initializing', $module); |
||
| 86 | module.createID(); |
||
| 87 | module.bind.events(); |
||
| 88 | if(!module.exists() && settings.preserve) { |
||
| 89 | module.create(); |
||
| 90 | } |
||
| 91 | if(settings.observeChanges) { |
||
| 92 | module.observeChanges(); |
||
| 93 | } |
||
| 94 | module.instantiate(); |
||
| 95 | }, |
||
| 96 | |||
| 97 | instantiate: function() { |
||
| 98 | module.verbose('Storing instance', module); |
||
| 99 | instance = module; |
||
| 100 | $module |
||
| 101 | .data(moduleNamespace, instance) |
||
| 102 | ; |
||
| 103 | }, |
||
| 104 | |||
| 105 | observeChanges: function() { |
||
| 106 | if('MutationObserver' in window) { |
||
| 107 | documentObserver = new MutationObserver(module.event.documentChanged); |
||
| 108 | documentObserver.observe(document, { |
||
| 109 | childList : true, |
||
| 110 | subtree : true |
||
| 111 | }); |
||
| 112 | module.debug('Setting up mutation observer', documentObserver); |
||
| 113 | } |
||
| 114 | }, |
||
| 115 | |||
| 116 | refresh: function() { |
||
| 117 | if(settings.popup) { |
||
| 118 | $popup = $(settings.popup).eq(0); |
||
| 119 | } |
||
| 120 | else { |
||
| 121 | if(settings.inline) { |
||
| 122 | $popup = $target.nextAll(selector.popup).eq(0); |
||
| 123 | settings.popup = $popup; |
||
| 124 | } |
||
| 125 | } |
||
| 126 | if(settings.popup) { |
||
| 127 | $popup.addClass(className.loading); |
||
| 128 | $offsetParent = module.get.offsetParent($target); |
||
| 129 | $popup.removeClass(className.loading); |
||
| 130 | if(settings.movePopup && module.has.popup() && module.get.offsetParent($popup)[0] !== $offsetParent[0]) { |
||
| 131 | module.debug('Moving popup to the same offset parent as target'); |
||
| 132 | $popup |
||
| 133 | .detach() |
||
| 134 | .appendTo($offsetParent) |
||
| 135 | ; |
||
| 136 | } |
||
| 137 | } |
||
| 138 | else { |
||
| 139 | $offsetParent = (settings.inline) |
||
| 140 | ? module.get.offsetParent($target) |
||
| 141 | : module.has.popup() |
||
| 142 | ? module.get.offsetParent($target) |
||
| 143 | : $body |
||
| 144 | ; |
||
| 145 | } |
||
| 146 | if( $offsetParent.is('html') && $offsetParent[0] !== $body[0] ) { |
||
| 147 | module.debug('Setting page as offset parent'); |
||
| 148 | $offsetParent = $body; |
||
| 149 | } |
||
| 150 | if( module.get.variation() ) { |
||
| 151 | module.set.variation(); |
||
| 152 | } |
||
| 153 | }, |
||
| 154 | |||
| 155 | reposition: function() { |
||
| 156 | module.refresh(); |
||
| 157 | module.set.position(); |
||
| 158 | }, |
||
| 159 | |||
| 160 | destroy: function() { |
||
| 161 | module.debug('Destroying previous module'); |
||
| 162 | if(documentObserver) { |
||
| 163 | documentObserver.disconnect(); |
||
| 164 | } |
||
| 165 | // remove element only if was created dynamically |
||
| 166 | if($popup && !settings.preserve) { |
||
| 167 | module.removePopup(); |
||
| 168 | } |
||
| 169 | // clear all timeouts |
||
| 170 | clearTimeout(module.hideTimer); |
||
| 171 | clearTimeout(module.showTimer); |
||
| 172 | // remove events |
||
| 173 | module.unbind.close(); |
||
| 174 | module.unbind.events(); |
||
| 175 | $module |
||
| 176 | .removeData(moduleNamespace) |
||
| 177 | ; |
||
| 178 | }, |
||
| 179 | |||
| 180 | event: { |
||
| 181 | start: function(event) { |
||
| 182 | var |
||
| 183 | delay = ($.isPlainObject(settings.delay)) |
||
| 184 | ? settings.delay.show |
||
| 185 | : settings.delay |
||
| 186 | ; |
||
| 187 | clearTimeout(module.hideTimer); |
||
| 188 | if(!openedWithTouch) { |
||
| 189 | module.showTimer = setTimeout(module.show, delay); |
||
| 190 | } |
||
| 191 | }, |
||
| 192 | end: function() { |
||
| 193 | var |
||
| 194 | delay = ($.isPlainObject(settings.delay)) |
||
| 195 | ? settings.delay.hide |
||
| 196 | : settings.delay |
||
| 197 | ; |
||
| 198 | clearTimeout(module.showTimer); |
||
| 199 | module.hideTimer = setTimeout(module.hide, delay); |
||
| 200 | }, |
||
| 201 | touchstart: function(event) { |
||
| 202 | openedWithTouch = true; |
||
| 203 | module.show(); |
||
| 204 | }, |
||
| 205 | resize: function() { |
||
| 206 | if( module.is.visible() ) { |
||
| 207 | module.set.position(); |
||
| 208 | } |
||
| 209 | }, |
||
| 210 | documentChanged: function(mutations) { |
||
| 211 | [].forEach.call(mutations, function(mutation) { |
||
| 212 | if(mutation.removedNodes) { |
||
| 213 | [].forEach.call(mutation.removedNodes, function(node) { |
||
| 214 | if(node == element || $(node).find(element).length > 0) { |
||
| 215 | module.debug('Element removed from DOM, tearing down events'); |
||
| 216 | module.destroy(); |
||
| 217 | } |
||
| 218 | }); |
||
| 219 | } |
||
| 220 | }); |
||
| 221 | }, |
||
| 222 | hideGracefully: function(event) { |
||
| 223 | var |
||
| 224 | $target = $(event.target), |
||
| 225 | isInDOM = $.contains(document.documentElement, event.target), |
||
| 226 | inPopup = ($target.closest(selector.popup).length > 0) |
||
| 227 | ; |
||
| 228 | // don't close on clicks inside popup |
||
| 229 | if(event && !inPopup && isInDOM) { |
||
| 230 | module.debug('Click occurred outside popup hiding popup'); |
||
| 231 | module.hide(); |
||
| 232 | } |
||
| 233 | else { |
||
| 234 | module.debug('Click was inside popup, keeping popup open'); |
||
| 235 | } |
||
| 236 | } |
||
| 237 | }, |
||
| 238 | |||
| 239 | // generates popup html from metadata |
||
| 240 | create: function() { |
||
| 241 | var |
||
| 242 | html = module.get.html(), |
||
| 243 | title = module.get.title(), |
||
| 244 | content = module.get.content() |
||
| 245 | ; |
||
| 246 | |||
| 247 | if(html || content || title) { |
||
| 248 | module.debug('Creating pop-up html'); |
||
| 249 | if(!html) { |
||
| 250 | html = settings.templates.popup({ |
||
| 251 | title : title, |
||
| 252 | content : content |
||
| 253 | }); |
||
| 254 | } |
||
| 255 | $popup = $('<div/>') |
||
| 256 | .addClass(className.popup) |
||
| 257 | .data(metadata.activator, $module) |
||
| 258 | .html(html) |
||
| 259 | ; |
||
| 260 | if(settings.inline) { |
||
| 261 | module.verbose('Inserting popup element inline', $popup); |
||
| 262 | $popup |
||
| 263 | .insertAfter($module) |
||
| 264 | ; |
||
| 265 | } |
||
| 266 | else { |
||
| 267 | module.verbose('Appending popup element to body', $popup); |
||
| 268 | $popup |
||
| 269 | .appendTo( $context ) |
||
| 270 | ; |
||
| 271 | } |
||
| 272 | module.refresh(); |
||
| 273 | module.set.variation(); |
||
| 274 | |||
| 275 | if(settings.hoverable) { |
||
| 276 | module.bind.popup(); |
||
| 277 | } |
||
| 278 | settings.onCreate.call($popup, element); |
||
| 279 | } |
||
| 280 | else if($target.next(selector.popup).length !== 0) { |
||
| 281 | module.verbose('Pre-existing popup found'); |
||
| 282 | settings.inline = true; |
||
| 283 | settings.popup = $target.next(selector.popup).data(metadata.activator, $module); |
||
| 284 | module.refresh(); |
||
| 285 | if(settings.hoverable) { |
||
| 286 | module.bind.popup(); |
||
| 287 | } |
||
| 288 | } |
||
| 289 | else if(settings.popup) { |
||
| 290 | $(settings.popup).data(metadata.activator, $module); |
||
| 291 | module.verbose('Used popup specified in settings'); |
||
| 292 | module.refresh(); |
||
| 293 | if(settings.hoverable) { |
||
| 294 | module.bind.popup(); |
||
| 295 | } |
||
| 296 | } |
||
| 297 | else { |
||
| 298 | module.debug('No content specified skipping display', element); |
||
| 299 | } |
||
| 300 | }, |
||
| 301 | |||
| 302 | createID: function() { |
||
| 303 | id = (Math.random().toString(16) + '000000000').substr(2, 8); |
||
| 304 | elementNamespace = '.' + id; |
||
| 305 | module.verbose('Creating unique id for element', id); |
||
| 306 | }, |
||
| 307 | |||
| 308 | // determines popup state |
||
| 309 | toggle: function() { |
||
| 310 | module.debug('Toggling pop-up'); |
||
| 311 | if( module.is.hidden() ) { |
||
| 312 | module.debug('Popup is hidden, showing pop-up'); |
||
| 313 | module.unbind.close(); |
||
| 314 | module.show(); |
||
| 315 | } |
||
| 316 | else { |
||
| 317 | module.debug('Popup is visible, hiding pop-up'); |
||
| 318 | module.hide(); |
||
| 319 | } |
||
| 320 | }, |
||
| 321 | |||
| 322 | show: function(callback) { |
||
| 323 | callback = callback || function(){}; |
||
| 324 | module.debug('Showing pop-up', settings.transition); |
||
| 325 | if(module.is.hidden() && !( module.is.active() && module.is.dropdown()) ) { |
||
| 326 | if( !module.exists() ) { |
||
| 327 | module.create(); |
||
| 328 | } |
||
| 329 | if(settings.onShow.call($popup, element) === false) { |
||
| 330 | module.debug('onShow callback returned false, cancelling popup animation'); |
||
| 331 | return; |
||
| 332 | } |
||
| 333 | else if(!settings.preserve && !settings.popup) { |
||
| 334 | module.refresh(); |
||
| 335 | } |
||
| 336 | if( $popup && module.set.position() ) { |
||
| 337 | module.save.conditions(); |
||
| 338 | if(settings.exclusive) { |
||
| 339 | module.hideAll(); |
||
| 340 | } |
||
| 341 | module.animate.show(callback); |
||
| 342 | } |
||
| 343 | } |
||
| 344 | }, |
||
| 345 | |||
| 346 | |||
| 347 | hide: function(callback) { |
||
| 348 | callback = callback || function(){}; |
||
| 349 | if( module.is.visible() || module.is.animating() ) { |
||
| 350 | if(settings.onHide.call($popup, element) === false) { |
||
| 351 | module.debug('onHide callback returned false, cancelling popup animation'); |
||
| 352 | return; |
||
| 353 | } |
||
| 354 | module.remove.visible(); |
||
| 355 | module.unbind.close(); |
||
| 356 | module.restore.conditions(); |
||
| 357 | module.animate.hide(callback); |
||
| 358 | } |
||
| 359 | }, |
||
| 360 | |||
| 361 | hideAll: function() { |
||
| 362 | $(selector.popup) |
||
| 363 | .filter('.' + className.popupVisible) |
||
| 364 | .each(function() { |
||
| 365 | $(this) |
||
| 366 | .data(metadata.activator) |
||
| 367 | .popup('hide') |
||
| 368 | ; |
||
| 369 | }) |
||
| 370 | ; |
||
| 371 | }, |
||
| 372 | exists: function() { |
||
| 373 | if(!$popup) { |
||
| 374 | return false; |
||
| 375 | } |
||
| 376 | if(settings.inline || settings.popup) { |
||
| 377 | return ( module.has.popup() ); |
||
| 378 | } |
||
| 379 | else { |
||
| 380 | return ( $popup.closest($context).length >= 1 ) |
||
| 381 | ? true |
||
| 382 | : false |
||
| 383 | ; |
||
| 384 | } |
||
| 385 | }, |
||
| 386 | |||
| 387 | removePopup: function() { |
||
| 388 | if( module.has.popup() && !settings.popup) { |
||
| 389 | module.debug('Removing popup', $popup); |
||
| 390 | $popup.remove(); |
||
| 391 | $popup = undefined; |
||
| 392 | settings.onRemove.call($popup, element); |
||
| 393 | } |
||
| 394 | }, |
||
| 395 | |||
| 396 | save: { |
||
| 397 | conditions: function() { |
||
| 398 | module.cache = { |
||
| 399 | title: $module.attr('title') |
||
| 400 | }; |
||
| 401 | if (module.cache.title) { |
||
| 402 | $module.removeAttr('title'); |
||
| 403 | } |
||
| 404 | module.verbose('Saving original attributes', module.cache.title); |
||
| 405 | } |
||
| 406 | }, |
||
| 407 | restore: { |
||
| 408 | conditions: function() { |
||
| 409 | if(module.cache && module.cache.title) { |
||
| 410 | $module.attr('title', module.cache.title); |
||
| 411 | module.verbose('Restoring original attributes', module.cache.title); |
||
| 412 | } |
||
| 413 | return true; |
||
| 414 | } |
||
| 415 | }, |
||
| 416 | supports: { |
||
| 417 | svg: function() { |
||
| 418 | return (typeof SVGGraphicsElement === 'undefined'); |
||
| 419 | } |
||
| 420 | }, |
||
| 421 | animate: { |
||
| 422 | show: function(callback) { |
||
| 423 | callback = $.isFunction(callback) ? callback : function(){}; |
||
| 424 | if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) { |
||
| 425 | module.set.visible(); |
||
| 426 | $popup |
||
| 427 | .transition({ |
||
| 428 | animation : settings.transition + ' in', |
||
| 429 | queue : false, |
||
| 430 | debug : settings.debug, |
||
| 431 | verbose : settings.verbose, |
||
| 432 | duration : settings.duration, |
||
| 433 | onComplete : function() { |
||
| 434 | module.bind.close(); |
||
| 435 | callback.call($popup, element); |
||
| 436 | settings.onVisible.call($popup, element); |
||
| 437 | } |
||
| 438 | }) |
||
| 439 | ; |
||
| 440 | } |
||
| 441 | else { |
||
| 442 | module.error(error.noTransition); |
||
| 443 | } |
||
| 444 | }, |
||
| 445 | hide: function(callback) { |
||
| 446 | callback = $.isFunction(callback) ? callback : function(){}; |
||
| 447 | module.debug('Hiding pop-up'); |
||
| 448 | if(settings.onHide.call($popup, element) === false) { |
||
| 449 | module.debug('onHide callback returned false, cancelling popup animation'); |
||
| 450 | return; |
||
| 451 | } |
||
| 452 | if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) { |
||
| 453 | $popup |
||
| 454 | .transition({ |
||
| 455 | animation : settings.transition + ' out', |
||
| 456 | queue : false, |
||
| 457 | duration : settings.duration, |
||
| 458 | debug : settings.debug, |
||
| 459 | verbose : settings.verbose, |
||
| 460 | onComplete : function() { |
||
| 461 | module.reset(); |
||
| 462 | callback.call($popup, element); |
||
| 463 | settings.onHidden.call($popup, element); |
||
| 464 | } |
||
| 465 | }) |
||
| 466 | ; |
||
| 467 | } |
||
| 468 | else { |
||
| 469 | module.error(error.noTransition); |
||
| 470 | } |
||
| 471 | } |
||
| 472 | }, |
||
| 473 | |||
| 474 | change: { |
||
| 475 | content: function(html) { |
||
| 476 | $popup.html(html); |
||
| 477 | } |
||
| 478 | }, |
||
| 479 | |||
| 480 | get: { |
||
| 481 | html: function() { |
||
| 482 | $module.removeData(metadata.html); |
||
| 483 | return $module.data(metadata.html) || settings.html; |
||
| 484 | }, |
||
| 485 | title: function() { |
||
| 486 | $module.removeData(metadata.title); |
||
| 487 | return $module.data(metadata.title) || settings.title; |
||
| 488 | }, |
||
| 489 | content: function() { |
||
| 490 | $module.removeData(metadata.content); |
||
| 491 | return $module.data(metadata.content) || $module.attr('title') || settings.content; |
||
| 492 | }, |
||
| 493 | variation: function() { |
||
| 494 | $module.removeData(metadata.variation); |
||
| 495 | return $module.data(metadata.variation) || settings.variation; |
||
| 496 | }, |
||
| 497 | popup: function() { |
||
| 498 | return $popup; |
||
| 499 | }, |
||
| 500 | popupOffset: function() { |
||
| 501 | return $popup.offset(); |
||
| 502 | }, |
||
| 503 | calculations: function() { |
||
| 504 | var |
||
| 505 | targetElement = $target[0], |
||
| 506 | isWindow = ($boundary[0] == window), |
||
| 507 | targetPosition = (settings.inline || (settings.popup && settings.movePopup)) |
||
| 508 | ? $target.position() |
||
| 509 | : $target.offset(), |
||
| 510 | screenPosition = (isWindow) |
||
| 511 | ? { top: 0, left: 0 } |
||
| 512 | : $boundary.offset(), |
||
| 513 | calculations = {}, |
||
| 514 | scroll = (isWindow) |
||
| 515 | ? { top: $window.scrollTop(), left: $window.scrollLeft() } |
||
| 516 | : { top: 0, left: 0}, |
||
| 517 | screen |
||
| 518 | ; |
||
| 519 | calculations = { |
||
| 520 | // element which is launching popup |
||
| 521 | target : { |
||
| 522 | element : $target[0], |
||
| 523 | width : $target.outerWidth(), |
||
| 524 | height : $target.outerHeight(), |
||
| 525 | top : targetPosition.top, |
||
| 526 | left : targetPosition.left, |
||
| 527 | margin : {} |
||
| 528 | }, |
||
| 529 | // popup itself |
||
| 530 | popup : { |
||
| 531 | width : $popup.outerWidth(), |
||
| 532 | height : $popup.outerHeight() |
||
| 533 | }, |
||
| 534 | // offset container (or 3d context) |
||
| 535 | parent : { |
||
| 536 | width : $offsetParent.outerWidth(), |
||
| 537 | height : $offsetParent.outerHeight() |
||
| 538 | }, |
||
| 539 | // screen boundaries |
||
| 540 | screen : { |
||
| 541 | top : screenPosition.top, |
||
| 542 | left : screenPosition.left, |
||
| 543 | scroll: { |
||
| 544 | top : scroll.top, |
||
| 545 | left : scroll.left |
||
| 546 | }, |
||
| 547 | width : $boundary.width(), |
||
| 548 | height : $boundary.height() |
||
| 549 | } |
||
| 550 | }; |
||
| 551 | |||
| 552 | // add in container calcs if fluid |
||
| 553 | if( settings.setFluidWidth && module.is.fluid() ) { |
||
| 554 | calculations.container = { |
||
| 555 | width: $popup.parent().outerWidth() |
||
| 556 | }; |
||
| 557 | calculations.popup.width = calculations.container.width; |
||
| 558 | } |
||
| 559 | |||
| 560 | // add in margins if inline |
||
| 561 | calculations.target.margin.top = (settings.inline) |
||
| 562 | ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10) |
||
| 563 | : 0 |
||
| 564 | ; |
||
| 565 | calculations.target.margin.left = (settings.inline) |
||
| 566 | ? module.is.rtl() |
||
| 567 | ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-right'), 10) |
||
| 568 | : parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left'), 10) |
||
| 569 | : 0 |
||
| 570 | ; |
||
| 571 | // calculate screen boundaries |
||
| 572 | screen = calculations.screen; |
||
| 573 | calculations.boundary = { |
||
| 574 | top : screen.top + screen.scroll.top, |
||
| 575 | bottom : screen.top + screen.scroll.top + screen.height, |
||
| 576 | left : screen.left + screen.scroll.left, |
||
| 577 | right : screen.left + screen.scroll.left + screen.width |
||
| 578 | }; |
||
| 579 | return calculations; |
||
| 580 | }, |
||
| 581 | id: function() { |
||
| 582 | return id; |
||
| 583 | }, |
||
| 584 | startEvent: function() { |
||
| 585 | if(settings.on == 'hover') { |
||
| 586 | return 'mouseenter'; |
||
| 587 | } |
||
| 588 | else if(settings.on == 'focus') { |
||
| 589 | return 'focus'; |
||
| 590 | } |
||
| 591 | return false; |
||
| 592 | }, |
||
| 593 | scrollEvent: function() { |
||
| 594 | return 'scroll'; |
||
| 595 | }, |
||
| 596 | endEvent: function() { |
||
| 597 | if(settings.on == 'hover') { |
||
| 598 | return 'mouseleave'; |
||
| 599 | } |
||
| 600 | else if(settings.on == 'focus') { |
||
| 601 | return 'blur'; |
||
| 602 | } |
||
| 603 | return false; |
||
| 604 | }, |
||
| 605 | distanceFromBoundary: function(offset, calculations) { |
||
| 606 | var |
||
| 607 | distanceFromBoundary = {}, |
||
| 608 | popup, |
||
| 609 | boundary |
||
| 610 | ; |
||
| 611 | calculations = calculations || module.get.calculations(); |
||
| 612 | |||
| 613 | // shorthand |
||
| 614 | popup = calculations.popup; |
||
| 615 | boundary = calculations.boundary; |
||
| 616 | |||
| 617 | if(offset) { |
||
| 618 | distanceFromBoundary = { |
||
| 619 | top : (offset.top - boundary.top), |
||
| 620 | left : (offset.left - boundary.left), |
||
| 621 | right : (boundary.right - (offset.left + popup.width) ), |
||
| 622 | bottom : (boundary.bottom - (offset.top + popup.height) ) |
||
| 623 | }; |
||
| 624 | module.verbose('Distance from boundaries determined', offset, distanceFromBoundary); |
||
| 625 | } |
||
| 626 | return distanceFromBoundary; |
||
| 627 | }, |
||
| 628 | offsetParent: function($target) { |
||
| 629 | var |
||
| 630 | element = ($target !== undefined) |
||
| 631 | ? $target[0] |
||
| 632 | : $module[0], |
||
| 633 | parentNode = element.parentNode, |
||
| 634 | $node = $(parentNode) |
||
| 635 | ; |
||
| 636 | if(parentNode) { |
||
| 637 | var |
||
| 638 | is2D = ($node.css('transform') === 'none'), |
||
| 639 | isStatic = ($node.css('position') === 'static'), |
||
| 640 | isHTML = $node.is('html') |
||
| 641 | ; |
||
| 642 | while(parentNode && !isHTML && isStatic && is2D) { |
||
| 643 | parentNode = parentNode.parentNode; |
||
| 644 | $node = $(parentNode); |
||
| 645 | is2D = ($node.css('transform') === 'none'); |
||
| 646 | isStatic = ($node.css('position') === 'static'); |
||
| 647 | isHTML = $node.is('html'); |
||
| 648 | } |
||
| 649 | } |
||
| 650 | return ($node && $node.length > 0) |
||
| 651 | ? $node |
||
| 652 | : $() |
||
| 653 | ; |
||
| 654 | }, |
||
| 655 | positions: function() { |
||
| 656 | return { |
||
| 657 | 'top left' : false, |
||
| 658 | 'top center' : false, |
||
| 659 | 'top right' : false, |
||
| 660 | 'bottom left' : false, |
||
| 661 | 'bottom center' : false, |
||
| 662 | 'bottom right' : false, |
||
| 663 | 'left center' : false, |
||
| 664 | 'right center' : false |
||
| 665 | }; |
||
| 666 | }, |
||
| 667 | nextPosition: function(position) { |
||
| 668 | var |
||
| 669 | positions = position.split(' '), |
||
| 670 | verticalPosition = positions[0], |
||
| 671 | horizontalPosition = positions[1], |
||
| 672 | opposite = { |
||
| 673 | top : 'bottom', |
||
| 674 | bottom : 'top', |
||
| 675 | left : 'right', |
||
| 676 | right : 'left' |
||
| 677 | }, |
||
| 678 | adjacent = { |
||
| 679 | left : 'center', |
||
| 680 | center : 'right', |
||
| 681 | right : 'left' |
||
| 682 | }, |
||
| 683 | backup = { |
||
| 684 | 'top left' : 'top center', |
||
| 685 | 'top center' : 'top right', |
||
| 686 | 'top right' : 'right center', |
||
| 687 | 'right center' : 'bottom right', |
||
| 688 | 'bottom right' : 'bottom center', |
||
| 689 | 'bottom center' : 'bottom left', |
||
| 690 | 'bottom left' : 'left center', |
||
| 691 | 'left center' : 'top left' |
||
| 692 | }, |
||
| 693 | adjacentsAvailable = (verticalPosition == 'top' || verticalPosition == 'bottom'), |
||
| 694 | oppositeTried = false, |
||
| 695 | adjacentTried = false, |
||
| 696 | nextPosition = false |
||
| 697 | ; |
||
| 698 | if(!triedPositions) { |
||
| 699 | module.verbose('All available positions available'); |
||
| 700 | triedPositions = module.get.positions(); |
||
| 701 | } |
||
| 702 | |||
| 703 | module.debug('Recording last position tried', position); |
||
| 704 | triedPositions[position] = true; |
||
| 705 | |||
| 706 | if(settings.prefer === 'opposite') { |
||
| 707 | nextPosition = [opposite[verticalPosition], horizontalPosition]; |
||
| 708 | nextPosition = nextPosition.join(' '); |
||
| 709 | oppositeTried = (triedPositions[nextPosition] === true); |
||
| 710 | module.debug('Trying opposite strategy', nextPosition); |
||
| 711 | } |
||
| 712 | if((settings.prefer === 'adjacent') && adjacentsAvailable ) { |
||
| 713 | nextPosition = [verticalPosition, adjacent[horizontalPosition]]; |
||
| 714 | nextPosition = nextPosition.join(' '); |
||
| 715 | adjacentTried = (triedPositions[nextPosition] === true); |
||
| 716 | module.debug('Trying adjacent strategy', nextPosition); |
||
| 717 | } |
||
| 718 | if(adjacentTried || oppositeTried) { |
||
| 719 | module.debug('Using backup position', nextPosition); |
||
| 720 | nextPosition = backup[position]; |
||
| 721 | } |
||
| 722 | return nextPosition; |
||
| 723 | } |
||
| 724 | }, |
||
| 725 | |||
| 726 | set: { |
||
| 727 | position: function(position, calculations) { |
||
| 728 | |||
| 729 | // exit conditions |
||
| 730 | if($target.length === 0 || $popup.length === 0) { |
||
| 731 | module.error(error.notFound); |
||
| 732 | return; |
||
| 733 | } |
||
| 734 | var |
||
| 735 | offset, |
||
| 736 | distanceAway, |
||
| 737 | target, |
||
| 738 | popup, |
||
| 739 | parent, |
||
| 740 | positioning, |
||
| 741 | popupOffset, |
||
| 742 | distanceFromBoundary |
||
| 743 | ; |
||
| 744 | |||
| 745 | calculations = calculations || module.get.calculations(); |
||
| 746 | position = position || $module.data(metadata.position) || settings.position; |
||
| 747 | |||
| 748 | offset = $module.data(metadata.offset) || settings.offset; |
||
| 749 | distanceAway = settings.distanceAway; |
||
| 750 | |||
| 751 | // shorthand |
||
| 752 | target = calculations.target; |
||
| 753 | popup = calculations.popup; |
||
| 754 | parent = calculations.parent; |
||
| 755 | |||
| 756 | if(target.width === 0 && target.height === 0 && !module.is.svg(target.element)) { |
||
| 757 | module.debug('Popup target is hidden, no action taken'); |
||
| 758 | return false; |
||
| 759 | } |
||
| 760 | |||
| 761 | if(settings.inline) { |
||
| 762 | module.debug('Adding margin to calculation', target.margin); |
||
| 763 | if(position == 'left center' || position == 'right center') { |
||
| 764 | offset += target.margin.top; |
||
| 765 | distanceAway += -target.margin.left; |
||
| 766 | } |
||
| 767 | else if (position == 'top left' || position == 'top center' || position == 'top right') { |
||
| 768 | offset += target.margin.left; |
||
| 769 | distanceAway -= target.margin.top; |
||
| 770 | } |
||
| 771 | else { |
||
| 772 | offset += target.margin.left; |
||
| 773 | distanceAway += target.margin.top; |
||
| 774 | } |
||
| 775 | } |
||
| 776 | |||
| 777 | module.debug('Determining popup position from calculations', position, calculations); |
||
| 778 | |||
| 779 | if (module.is.rtl()) { |
||
| 780 | position = position.replace(/left|right/g, function (match) { |
||
| 781 | return (match == 'left') |
||
| 782 | ? 'right' |
||
| 783 | : 'left' |
||
| 784 | ; |
||
| 785 | }); |
||
| 786 | module.debug('RTL: Popup position updated', position); |
||
| 787 | } |
||
| 788 | |||
| 789 | // if last attempt use specified last resort position |
||
| 790 | if(searchDepth == settings.maxSearchDepth && typeof settings.lastResort === 'string') { |
||
| 791 | position = settings.lastResort; |
||
| 792 | } |
||
| 793 | |||
| 794 | switch (position) { |
||
| 795 | case 'top left': |
||
| 796 | positioning = { |
||
| 797 | top : 'auto', |
||
| 798 | bottom : parent.height - target.top + distanceAway, |
||
| 799 | left : target.left + offset, |
||
| 800 | right : 'auto' |
||
| 801 | }; |
||
| 802 | break; |
||
| 803 | case 'top center': |
||
| 804 | positioning = { |
||
| 805 | bottom : parent.height - target.top + distanceAway, |
||
| 806 | left : target.left + (target.width / 2) - (popup.width / 2) + offset, |
||
| 807 | top : 'auto', |
||
| 808 | right : 'auto' |
||
| 809 | }; |
||
| 810 | break; |
||
| 811 | case 'top right': |
||
| 812 | positioning = { |
||
| 813 | bottom : parent.height - target.top + distanceAway, |
||
| 814 | right : parent.width - target.left - target.width - offset, |
||
| 815 | top : 'auto', |
||
| 816 | left : 'auto' |
||
| 817 | }; |
||
| 818 | break; |
||
| 819 | case 'left center': |
||
| 820 | positioning = { |
||
| 821 | top : target.top + (target.height / 2) - (popup.height / 2) + offset, |
||
| 822 | right : parent.width - target.left + distanceAway, |
||
| 823 | left : 'auto', |
||
| 824 | bottom : 'auto' |
||
| 825 | }; |
||
| 826 | break; |
||
| 827 | case 'right center': |
||
| 828 | positioning = { |
||
| 829 | top : target.top + (target.height / 2) - (popup.height / 2) + offset, |
||
| 830 | left : target.left + target.width + distanceAway, |
||
| 831 | bottom : 'auto', |
||
| 832 | right : 'auto' |
||
| 833 | }; |
||
| 834 | break; |
||
| 835 | case 'bottom left': |
||
| 836 | positioning = { |
||
| 837 | top : target.top + target.height + distanceAway, |
||
| 838 | left : target.left + offset, |
||
| 839 | bottom : 'auto', |
||
| 840 | right : 'auto' |
||
| 841 | }; |
||
| 842 | break; |
||
| 843 | case 'bottom center': |
||
| 844 | positioning = { |
||
| 845 | top : target.top + target.height + distanceAway, |
||
| 846 | left : target.left + (target.width / 2) - (popup.width / 2) + offset, |
||
| 847 | bottom : 'auto', |
||
| 848 | right : 'auto' |
||
| 849 | }; |
||
| 850 | break; |
||
| 851 | case 'bottom right': |
||
| 852 | positioning = { |
||
| 853 | top : target.top + target.height + distanceAway, |
||
| 854 | right : parent.width - target.left - target.width - offset, |
||
| 855 | left : 'auto', |
||
| 856 | bottom : 'auto' |
||
| 857 | }; |
||
| 858 | break; |
||
| 859 | } |
||
| 860 | if(positioning === undefined) { |
||
| 861 | module.error(error.invalidPosition, position); |
||
| 862 | } |
||
| 863 | |||
| 864 | module.debug('Calculated popup positioning values', positioning); |
||
| 865 | |||
| 866 | // tentatively place on stage |
||
| 867 | $popup |
||
| 868 | .css(positioning) |
||
| 869 | .removeClass(className.position) |
||
| 870 | .addClass(position) |
||
| 871 | .addClass(className.loading) |
||
| 872 | ; |
||
| 873 | |||
| 874 | popupOffset = module.get.popupOffset(); |
||
| 875 | |||
| 876 | // see if any boundaries are surpassed with this tentative position |
||
| 877 | distanceFromBoundary = module.get.distanceFromBoundary(popupOffset, calculations); |
||
| 878 | |||
| 879 | if( module.is.offstage(distanceFromBoundary, position) ) { |
||
| 880 | module.debug('Position is outside viewport', position); |
||
| 881 | if(searchDepth < settings.maxSearchDepth) { |
||
| 882 | searchDepth++; |
||
| 883 | position = module.get.nextPosition(position); |
||
| 884 | module.debug('Trying new position', position); |
||
| 885 | return ($popup) |
||
| 886 | ? module.set.position(position, calculations) |
||
| 887 | : false |
||
| 888 | ; |
||
| 889 | } |
||
| 890 | else { |
||
| 891 | if(settings.lastResort) { |
||
| 892 | module.debug('No position found, showing with last position'); |
||
| 893 | } |
||
| 894 | else { |
||
| 895 | module.debug('Popup could not find a position to display', $popup); |
||
| 896 | module.error(error.cannotPlace, element); |
||
| 897 | module.remove.attempts(); |
||
| 898 | module.remove.loading(); |
||
| 899 | module.reset(); |
||
| 900 | settings.onUnplaceable.call($popup, element); |
||
| 901 | return false; |
||
| 902 | } |
||
| 903 | } |
||
| 904 | } |
||
| 905 | module.debug('Position is on stage', position); |
||
| 906 | module.remove.attempts(); |
||
| 907 | module.remove.loading(); |
||
| 908 | if( settings.setFluidWidth && module.is.fluid() ) { |
||
| 909 | module.set.fluidWidth(calculations); |
||
| 910 | } |
||
| 911 | return true; |
||
| 912 | }, |
||
| 913 | |||
| 914 | fluidWidth: function(calculations) { |
||
| 915 | calculations = calculations || module.get.calculations(); |
||
| 916 | module.debug('Automatically setting element width to parent width', calculations.parent.width); |
||
| 917 | $popup.css('width', calculations.container.width); |
||
| 918 | }, |
||
| 919 | |||
| 920 | variation: function(variation) { |
||
| 921 | variation = variation || module.get.variation(); |
||
| 922 | if(variation && module.has.popup() ) { |
||
| 923 | module.verbose('Adding variation to popup', variation); |
||
| 924 | $popup.addClass(variation); |
||
| 925 | } |
||
| 926 | }, |
||
| 927 | |||
| 928 | visible: function() { |
||
| 929 | $module.addClass(className.visible); |
||
| 930 | } |
||
| 931 | }, |
||
| 932 | |||
| 933 | remove: { |
||
| 934 | loading: function() { |
||
| 935 | $popup.removeClass(className.loading); |
||
| 936 | }, |
||
| 937 | variation: function(variation) { |
||
| 938 | variation = variation || module.get.variation(); |
||
| 939 | if(variation) { |
||
| 940 | module.verbose('Removing variation', variation); |
||
| 941 | $popup.removeClass(variation); |
||
| 942 | } |
||
| 943 | }, |
||
| 944 | visible: function() { |
||
| 945 | $module.removeClass(className.visible); |
||
| 946 | }, |
||
| 947 | attempts: function() { |
||
| 948 | module.verbose('Resetting all searched positions'); |
||
| 949 | searchDepth = 0; |
||
| 950 | triedPositions = false; |
||
| 951 | } |
||
| 952 | }, |
||
| 953 | |||
| 954 | bind: { |
||
| 955 | events: function() { |
||
| 956 | module.debug('Binding popup events to module'); |
||
| 957 | if(settings.on == 'click') { |
||
| 958 | $module |
||
| 959 | .on('click' + eventNamespace, module.toggle) |
||
| 960 | ; |
||
| 961 | } |
||
| 962 | if(settings.on == 'hover' && hasTouch) { |
||
| 963 | $module |
||
| 964 | .on('touchstart' + eventNamespace, module.event.touchstart) |
||
| 965 | ; |
||
| 966 | } |
||
| 967 | if( module.get.startEvent() ) { |
||
| 968 | $module |
||
| 969 | .on(module.get.startEvent() + eventNamespace, module.event.start) |
||
| 970 | .on(module.get.endEvent() + eventNamespace, module.event.end) |
||
| 971 | ; |
||
| 972 | } |
||
| 973 | if(settings.target) { |
||
| 974 | module.debug('Target set to element', $target); |
||
| 975 | } |
||
| 976 | $window.on('resize' + elementNamespace, module.event.resize); |
||
| 977 | }, |
||
| 978 | popup: function() { |
||
| 979 | module.verbose('Allowing hover events on popup to prevent closing'); |
||
| 980 | if( $popup && module.has.popup() ) { |
||
| 981 | $popup |
||
| 982 | .on('mouseenter' + eventNamespace, module.event.start) |
||
| 983 | .on('mouseleave' + eventNamespace, module.event.end) |
||
| 984 | ; |
||
| 985 | } |
||
| 986 | }, |
||
| 987 | close: function() { |
||
| 988 | if(settings.hideOnScroll === true || (settings.hideOnScroll == 'auto' && settings.on != 'click')) { |
||
| 989 | module.bind.closeOnScroll(); |
||
| 990 | } |
||
| 991 | if(settings.on == 'hover' && openedWithTouch) { |
||
| 992 | module.bind.touchClose(); |
||
| 993 | } |
||
| 994 | if(settings.on == 'click' && settings.closable) { |
||
| 995 | module.bind.clickaway(); |
||
| 996 | } |
||
| 997 | }, |
||
| 998 | closeOnScroll: function() { |
||
| 999 | module.verbose('Binding scroll close event to document'); |
||
| 1000 | $scrollContext |
||
| 1001 | .one(module.get.scrollEvent() + elementNamespace, module.event.hideGracefully) |
||
| 1002 | ; |
||
| 1003 | }, |
||
| 1004 | touchClose: function() { |
||
| 1005 | module.verbose('Binding popup touchclose event to document'); |
||
| 1006 | $document |
||
| 1007 | .on('touchstart' + elementNamespace, function(event) { |
||
| 1008 | module.verbose('Touched away from popup'); |
||
| 1009 | module.event.hideGracefully.call(element, event); |
||
| 1010 | }) |
||
| 1011 | ; |
||
| 1012 | }, |
||
| 1013 | clickaway: function() { |
||
| 1014 | module.verbose('Binding popup close event to document'); |
||
| 1015 | $document |
||
| 1016 | .on('click' + elementNamespace, function(event) { |
||
| 1017 | module.verbose('Clicked away from popup'); |
||
| 1018 | module.event.hideGracefully.call(element, event); |
||
| 1019 | }) |
||
| 1020 | ; |
||
| 1021 | } |
||
| 1022 | }, |
||
| 1023 | |||
| 1024 | unbind: { |
||
| 1025 | events: function() { |
||
| 1026 | $window |
||
| 1027 | .off(elementNamespace) |
||
| 1028 | ; |
||
| 1029 | $module |
||
| 1030 | .off(eventNamespace) |
||
| 1031 | ; |
||
| 1032 | }, |
||
| 1033 | close: function() { |
||
| 1034 | $document |
||
| 1035 | .off(elementNamespace) |
||
| 1036 | ; |
||
| 1037 | $scrollContext |
||
| 1038 | .off(elementNamespace) |
||
| 1039 | ; |
||
| 1040 | }, |
||
| 1041 | }, |
||
| 1042 | |||
| 1043 | has: { |
||
| 1044 | popup: function() { |
||
| 1045 | return ($popup && $popup.length > 0); |
||
| 1046 | } |
||
| 1047 | }, |
||
| 1048 | |||
| 1049 | is: { |
||
| 1050 | offstage: function(distanceFromBoundary, position) { |
||
| 1051 | var |
||
| 1052 | offstage = [] |
||
| 1053 | ; |
||
| 1054 | // return boundaries that have been surpassed |
||
| 1055 | $.each(distanceFromBoundary, function(direction, distance) { |
||
| 1056 | if(distance < -settings.jitter) { |
||
| 1057 | module.debug('Position exceeds allowable distance from edge', direction, distance, position); |
||
| 1058 | offstage.push(direction); |
||
| 1059 | } |
||
| 1060 | }); |
||
| 1061 | if(offstage.length > 0) { |
||
| 1062 | return true; |
||
| 1063 | } |
||
| 1064 | else { |
||
| 1065 | return false; |
||
| 1066 | } |
||
| 1067 | }, |
||
| 1068 | svg: function(element) { |
||
| 1069 | return module.supports.svg() && (element instanceof SVGGraphicsElement); |
||
| 1070 | }, |
||
| 1071 | active: function() { |
||
| 1072 | return $module.hasClass(className.active); |
||
| 1073 | }, |
||
| 1074 | animating: function() { |
||
| 1075 | return ($popup !== undefined && $popup.hasClass(className.animating) ); |
||
| 1076 | }, |
||
| 1077 | fluid: function() { |
||
| 1078 | return ($popup !== undefined && $popup.hasClass(className.fluid)); |
||
| 1079 | }, |
||
| 1080 | visible: function() { |
||
| 1081 | return ($popup !== undefined && $popup.hasClass(className.popupVisible)); |
||
| 1082 | }, |
||
| 1083 | dropdown: function() { |
||
| 1084 | return $module.hasClass(className.dropdown); |
||
| 1085 | }, |
||
| 1086 | hidden: function() { |
||
| 1087 | return !module.is.visible(); |
||
| 1088 | }, |
||
| 1089 | rtl: function () { |
||
| 1090 | return $module.css('direction') == 'rtl'; |
||
| 1091 | } |
||
| 1092 | }, |
||
| 1093 | |||
| 1094 | reset: function() { |
||
| 1095 | module.remove.visible(); |
||
| 1096 | if(settings.preserve) { |
||
| 1097 | if($.fn.transition !== undefined) { |
||
| 1098 | $popup |
||
| 1099 | .transition('remove transition') |
||
| 1100 | ; |
||
| 1101 | } |
||
| 1102 | } |
||
| 1103 | else { |
||
| 1104 | module.removePopup(); |
||
| 1105 | } |
||
| 1106 | }, |
||
| 1107 | |||
| 1108 | setting: function(name, value) { |
||
| 1109 | if( $.isPlainObject(name) ) { |
||
| 1110 | $.extend(true, settings, name); |
||
| 1111 | } |
||
| 1112 | else if(value !== undefined) { |
||
| 1113 | settings[name] = value; |
||
| 1114 | } |
||
| 1115 | else { |
||
| 1116 | return settings[name]; |
||
| 1117 | } |
||
| 1118 | }, |
||
| 1119 | internal: function(name, value) { |
||
| 1120 | if( $.isPlainObject(name) ) { |
||
| 1121 | $.extend(true, module, name); |
||
| 1122 | } |
||
| 1123 | else if(value !== undefined) { |
||
| 1124 | module[name] = value; |
||
| 1125 | } |
||
| 1126 | else { |
||
| 1127 | return module[name]; |
||
| 1128 | } |
||
| 1129 | }, |
||
| 1130 | debug: function() { |
||
| 1131 | if(!settings.silent && settings.debug) { |
||
| 1132 | if(settings.performance) { |
||
| 1133 | module.performance.log(arguments); |
||
| 1134 | } |
||
| 1135 | else { |
||
| 1136 | module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
||
| 1137 | module.debug.apply(console, arguments); |
||
| 1138 | } |
||
| 1139 | } |
||
| 1140 | }, |
||
| 1141 | verbose: function() { |
||
| 1142 | if(!settings.silent && settings.verbose && settings.debug) { |
||
| 1143 | if(settings.performance) { |
||
| 1144 | module.performance.log(arguments); |
||
| 1145 | } |
||
| 1146 | else { |
||
| 1147 | module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
||
| 1148 | module.verbose.apply(console, arguments); |
||
| 1149 | } |
||
| 1150 | } |
||
| 1151 | }, |
||
| 1152 | error: function() { |
||
| 1153 | if(!settings.silent) { |
||
| 1154 | module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); |
||
| 1155 | module.error.apply(console, arguments); |
||
| 1156 | } |
||
| 1157 | }, |
||
| 1158 | performance: { |
||
| 1159 | log: function(message) { |
||
| 1160 | var |
||
| 1161 | currentTime, |
||
| 1162 | executionTime, |
||
| 1163 | previousTime |
||
| 1164 | ; |
||
| 1165 | if(settings.performance) { |
||
| 1166 | currentTime = new Date().getTime(); |
||
| 1167 | previousTime = time || currentTime; |
||
| 1168 | executionTime = currentTime - previousTime; |
||
| 1169 | time = currentTime; |
||
| 1170 | performance.push({ |
||
| 1171 | 'Name' : message[0], |
||
| 1172 | 'Arguments' : [].slice.call(message, 1) || '', |
||
| 1173 | 'Element' : element, |
||
| 1174 | 'Execution Time' : executionTime |
||
| 1175 | }); |
||
| 1176 | } |
||
| 1177 | clearTimeout(module.performance.timer); |
||
| 1178 | module.performance.timer = setTimeout(module.performance.display, 500); |
||
| 1179 | }, |
||
| 1180 | display: function() { |
||
| 1181 | var |
||
| 1182 | title = settings.name + ':', |
||
| 1183 | totalTime = 0 |
||
| 1184 | ; |
||
| 1185 | time = false; |
||
| 1186 | clearTimeout(module.performance.timer); |
||
| 1187 | $.each(performance, function(index, data) { |
||
| 1188 | totalTime += data['Execution Time']; |
||
| 1189 | }); |
||
| 1190 | title += ' ' + totalTime + 'ms'; |
||
| 1191 | if(moduleSelector) { |
||
| 1192 | title += ' \'' + moduleSelector + '\''; |
||
| 1193 | } |
||
| 1194 | if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { |
||
| 1195 | console.groupCollapsed(title); |
||
| 1196 | if(console.table) { |
||
| 1197 | console.table(performance); |
||
| 1198 | } |
||
| 1199 | else { |
||
| 1200 | $.each(performance, function(index, data) { |
||
| 1201 | console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); |
||
| 1202 | }); |
||
| 1203 | } |
||
| 1204 | console.groupEnd(); |
||
| 1205 | } |
||
| 1206 | performance = []; |
||
| 1207 | } |
||
| 1208 | }, |
||
| 1209 | invoke: function(query, passedArguments, context) { |
||
| 1210 | var |
||
| 1211 | object = instance, |
||
| 1212 | maxDepth, |
||
| 1213 | found, |
||
| 1214 | response |
||
| 1215 | ; |
||
| 1216 | passedArguments = passedArguments || queryArguments; |
||
| 1217 | context = element || context; |
||
| 1218 | if(typeof query == 'string' && object !== undefined) { |
||
| 1219 | query = query.split(/[\. ]/); |
||
| 1220 | maxDepth = query.length - 1; |
||
| 1221 | $.each(query, function(depth, value) { |
||
| 1222 | var camelCaseValue = (depth != maxDepth) |
||
| 1223 | ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) |
||
| 1224 | : query |
||
| 1225 | ; |
||
| 1226 | if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { |
||
| 1227 | object = object[camelCaseValue]; |
||
| 1228 | } |
||
| 1229 | else if( object[camelCaseValue] !== undefined ) { |
||
| 1230 | found = object[camelCaseValue]; |
||
| 1231 | return false; |
||
| 1232 | } |
||
| 1233 | else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { |
||
| 1234 | object = object[value]; |
||
| 1235 | } |
||
| 1236 | else if( object[value] !== undefined ) { |
||
| 1237 | found = object[value]; |
||
| 1238 | return false; |
||
| 1239 | } |
||
| 1240 | else { |
||
| 1241 | return false; |
||
| 1242 | } |
||
| 1243 | }); |
||
| 1244 | } |
||
| 1245 | if ( $.isFunction( found ) ) { |
||
| 1246 | response = found.apply(context, passedArguments); |
||
| 1247 | } |
||
| 1248 | else if(found !== undefined) { |
||
| 1249 | response = found; |
||
| 1250 | } |
||
| 1251 | if($.isArray(returnedValue)) { |
||
| 1252 | returnedValue.push(response); |
||
| 1253 | } |
||
| 1254 | else if(returnedValue !== undefined) { |
||
| 1255 | returnedValue = [returnedValue, response]; |
||
| 1256 | } |
||
| 1257 | else if(response !== undefined) { |
||
| 1258 | returnedValue = response; |
||
| 1259 | } |
||
| 1260 | return found; |
||
| 1261 | } |
||
| 1262 | }; |
||
| 1263 | |||
| 1264 | if(methodInvoked) { |
||
| 1265 | if(instance === undefined) { |
||
| 1266 | module.initialize(); |
||
| 1267 | } |
||
| 1268 | module.invoke(query); |
||
| 1269 | } |
||
| 1270 | else { |
||
| 1271 | if(instance !== undefined) { |
||
| 1272 | instance.invoke('destroy'); |
||
| 1273 | } |
||
| 1274 | module.initialize(); |
||
| 1275 | } |
||
| 1276 | }) |
||
| 1277 | ; |
||
| 1278 | |||
| 1279 | return (returnedValue !== undefined) |
||
| 1280 | ? returnedValue |
||
| 1281 | : this |
||
| 1282 | ; |
||
| 1283 | }; |
||
| 1284 | |||
| 1285 | $.fn.popup.settings = { |
||
| 1286 | |||
| 1287 | name : 'Popup', |
||
| 1288 | |||
| 1289 | // module settings |
||
| 1290 | silent : false, |
||
| 1291 | debug : false, |
||
| 1292 | verbose : false, |
||
| 1293 | performance : true, |
||
| 1294 | namespace : 'popup', |
||
| 1295 | |||
| 1296 | // whether it should use dom mutation observers |
||
| 1297 | observeChanges : true, |
||
| 1298 | |||
| 1299 | // callback only when element added to dom |
||
| 1300 | onCreate : function(){}, |
||
| 1301 | |||
| 1302 | // callback before element removed from dom |
||
| 1303 | onRemove : function(){}, |
||
| 1304 | |||
| 1305 | // callback before show animation |
||
| 1306 | onShow : function(){}, |
||
| 1307 | |||
| 1308 | // callback after show animation |
||
| 1309 | onVisible : function(){}, |
||
| 1310 | |||
| 1311 | // callback before hide animation |
||
| 1312 | onHide : function(){}, |
||
| 1313 | |||
| 1314 | // callback when popup cannot be positioned in visible screen |
||
| 1315 | onUnplaceable : function(){}, |
||
| 1316 | |||
| 1317 | // callback after hide animation |
||
| 1318 | onHidden : function(){}, |
||
| 1319 | |||
| 1320 | // when to show popup |
||
| 1321 | on : 'hover', |
||
| 1322 | |||
| 1323 | // element to use to determine if popup is out of boundary |
||
| 1324 | boundary : window, |
||
| 1325 | |||
| 1326 | // whether to add touchstart events when using hover |
||
| 1327 | addTouchEvents : true, |
||
| 1328 | |||
| 1329 | // default position relative to element |
||
| 1330 | position : 'top left', |
||
| 1331 | |||
| 1332 | // name of variation to use |
||
| 1333 | variation : '', |
||
| 1334 | |||
| 1335 | // whether popup should be moved to context |
||
| 1336 | movePopup : true, |
||
| 1337 | |||
| 1338 | // element which popup should be relative to |
||
| 1339 | target : false, |
||
| 1340 | |||
| 1341 | // jq selector or element that should be used as popup |
||
| 1342 | popup : false, |
||
| 1343 | |||
| 1344 | // popup should remain inline next to activator |
||
| 1345 | inline : false, |
||
| 1346 | |||
| 1347 | // popup should be removed from page on hide |
||
| 1348 | preserve : false, |
||
| 1349 | |||
| 1350 | // popup should not close when being hovered on |
||
| 1351 | hoverable : false, |
||
| 1352 | |||
| 1353 | // explicitly set content |
||
| 1354 | content : false, |
||
| 1355 | |||
| 1356 | // explicitly set html |
||
| 1357 | html : false, |
||
| 1358 | |||
| 1359 | // explicitly set title |
||
| 1360 | title : false, |
||
| 1361 | |||
| 1362 | // whether automatically close on clickaway when on click |
||
| 1363 | closable : true, |
||
| 1364 | |||
| 1365 | // automatically hide on scroll |
||
| 1366 | hideOnScroll : 'auto', |
||
| 1367 | |||
| 1368 | // hide other popups on show |
||
| 1369 | exclusive : false, |
||
| 1370 | |||
| 1371 | // context to attach popups |
||
| 1372 | context : 'body', |
||
| 1373 | |||
| 1374 | // context for binding scroll events |
||
| 1375 | scrollContext : window, |
||
| 1376 | |||
| 1377 | // position to prefer when calculating new position |
||
| 1378 | prefer : 'opposite', |
||
| 1379 | |||
| 1380 | // specify position to appear even if it doesn't fit |
||
| 1381 | lastResort : false, |
||
| 1382 | |||
| 1383 | // delay used to prevent accidental refiring of animations due to user error |
||
| 1384 | delay : { |
||
| 1385 | show : 50, |
||
| 1386 | hide : 70 |
||
| 1387 | }, |
||
| 1388 | |||
| 1389 | // whether fluid variation should assign width explicitly |
||
| 1390 | setFluidWidth : true, |
||
| 1391 | |||
| 1392 | // transition settings |
||
| 1393 | duration : 200, |
||
| 1394 | transition : 'scale', |
||
| 1395 | |||
| 1396 | // distance away from activating element in px |
||
| 1397 | distanceAway : 0, |
||
| 1398 | |||
| 1399 | // number of pixels an element is allowed to be "offstage" for a position to be chosen (allows for rounding) |
||
| 1400 | jitter : 2, |
||
| 1401 | |||
| 1402 | // offset on aligning axis from calculated position |
||
| 1403 | offset : 0, |
||
| 1404 | |||
| 1405 | // maximum times to look for a position before failing (9 positions total) |
||
| 1406 | maxSearchDepth : 15, |
||
| 1407 | |||
| 1408 | error: { |
||
| 1409 | invalidPosition : 'The position you specified is not a valid position', |
||
| 1410 | cannotPlace : 'Popup does not fit within the boundaries of the viewport', |
||
| 1411 | method : 'The method you called is not defined.', |
||
| 1412 | noTransition : 'This module requires ui transitions <https://github.com/Semantic-Org/UI-Transition>', |
||
| 1413 | notFound : 'The target or popup you specified does not exist on the page' |
||
| 1414 | }, |
||
| 1415 | |||
| 1416 | metadata: { |
||
| 1417 | activator : 'activator', |
||
| 1418 | content : 'content', |
||
| 1419 | html : 'html', |
||
| 1420 | offset : 'offset', |
||
| 1421 | position : 'position', |
||
| 1422 | title : 'title', |
||
| 1423 | variation : 'variation' |
||
| 1424 | }, |
||
| 1425 | |||
| 1426 | className : { |
||
| 1427 | active : 'active', |
||
| 1428 | animating : 'animating', |
||
| 1429 | dropdown : 'dropdown', |
||
| 1430 | fluid : 'fluid', |
||
| 1431 | loading : 'loading', |
||
| 1432 | popup : 'ui popup', |
||
| 1433 | position : 'top left center bottom right', |
||
| 1434 | visible : 'visible', |
||
| 1435 | popupVisible : 'visible' |
||
| 1436 | }, |
||
| 1437 | |||
| 1438 | selector : { |
||
| 1439 | popup : '.ui.popup' |
||
| 1440 | }, |
||
| 1441 | |||
| 1442 | templates: { |
||
| 1443 | escape: function(string) { |
||
| 1444 | var |
||
| 1445 | badChars = /[&<>"'`]/g, |
||
| 1446 | shouldEscape = /[&<>"'`]/, |
||
| 1447 | escape = { |
||
| 1448 | "&": "&", |
||
| 1449 | "<": "<", |
||
| 1450 | ">": ">", |
||
| 1451 | '"': """, |
||
| 1452 | "'": "'", |
||
| 1453 | "`": "`" |
||
| 1454 | }, |
||
| 1455 | escapedChar = function(chr) { |
||
| 1456 | return escape[chr]; |
||
| 1457 | } |
||
| 1458 | ; |
||
| 1459 | if(shouldEscape.test(string)) { |
||
| 1460 | return string.replace(badChars, escapedChar); |
||
| 1461 | } |
||
| 1462 | return string; |
||
| 1463 | }, |
||
| 1464 | popup: function(text) { |
||
| 1465 | var |
||
| 1466 | html = '', |
||
| 1467 | escape = $.fn.popup.settings.templates.escape |
||
| 1468 | ; |
||
| 1469 | if(typeof text !== undefined) { |
||
| 1470 | if(typeof text.title !== undefined && text.title) { |
||
| 1471 | text.title = escape(text.title); |
||
| 1472 | html += '<div class="header">' + text.title + '</div>'; |
||
| 1473 | } |
||
| 1474 | if(typeof text.content !== undefined && text.content) { |
||
| 1475 | text.content = escape(text.content); |
||
| 1476 | html += '<div class="content">' + text.content + '</div>'; |
||
| 1477 | } |
||
| 1478 | } |
||
| 1479 | return html; |
||
| 1480 | } |
||
| 1481 | } |
||
| 1482 | |||
| 1483 | }; |
||
| 1484 | |||
| 1485 | |||
| 1486 | })( jQuery, window, document ); |
||
| 1487 |