You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1224 lines
39 KiB

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