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.

1152 lines
36 KiB

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