gitea源码

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  1. /*!
  2. * # Fomantic-UI - Modal
  3. * http://github.com/fomantic/Fomantic-UI/
  4. *
  5. *
  6. * Released under the MIT license
  7. * http://opensource.org/licenses/MIT
  8. *
  9. */
  10. ;(function ($, window, document, undefined) {
  11. 'use strict';
  12. $.isFunction = $.isFunction || function(obj) {
  13. return typeof obj === "function" && typeof obj.nodeType !== "number";
  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. $.fn.modal = function(parameters) {
  22. var
  23. $allModules = $(this),
  24. $window = $(window),
  25. $document = $(document),
  26. $body = $('body'),
  27. moduleSelector = $allModules.selector || '',
  28. time = new Date().getTime(),
  29. performance = [],
  30. query = arguments[0],
  31. methodInvoked = (typeof query == 'string'),
  32. queryArguments = [].slice.call(arguments, 1),
  33. requestAnimationFrame = window.requestAnimationFrame
  34. || window.mozRequestAnimationFrame
  35. || window.webkitRequestAnimationFrame
  36. || window.msRequestAnimationFrame
  37. || function(callback) { setTimeout(callback, 0); },
  38. returnedValue
  39. ;
  40. $allModules
  41. .each(function() {
  42. var
  43. settings = ( $.isPlainObject(parameters) )
  44. ? $.extend(true, {}, $.fn.modal.settings, parameters)
  45. : $.extend({}, $.fn.modal.settings),
  46. selector = settings.selector,
  47. className = settings.className,
  48. namespace = settings.namespace,
  49. error = settings.error,
  50. eventNamespace = '.' + namespace,
  51. moduleNamespace = 'module-' + namespace,
  52. $module = $(this),
  53. $context = $(settings.context),
  54. $close = $module.find(selector.close),
  55. $allModals,
  56. $otherModals,
  57. $focusedElement,
  58. $dimmable,
  59. $dimmer,
  60. element = this,
  61. instance = $module.data(moduleNamespace),
  62. ignoreRepeatedEvents = false,
  63. initialMouseDownInModal,
  64. initialMouseDownInScrollbar,
  65. initialBodyMargin = '',
  66. tempBodyMargin = '',
  67. elementEventNamespace,
  68. id,
  69. observer,
  70. module
  71. ;
  72. module = {
  73. initialize: function() {
  74. module.cache = {};
  75. module.verbose('Initializing dimmer', $context);
  76. module.create.id();
  77. module.create.dimmer();
  78. if ( settings.allowMultiple ) {
  79. module.create.innerDimmer();
  80. }
  81. if (!settings.centered){
  82. $module.addClass('top aligned');
  83. }
  84. module.refreshModals();
  85. module.bind.events();
  86. if(settings.observeChanges) {
  87. module.observeChanges();
  88. }
  89. module.instantiate();
  90. },
  91. instantiate: function() {
  92. module.verbose('Storing instance of modal');
  93. instance = module;
  94. $module
  95. .data(moduleNamespace, instance)
  96. ;
  97. },
  98. create: {
  99. dimmer: function() {
  100. var
  101. defaultSettings = {
  102. debug : settings.debug,
  103. dimmerName : 'modals'
  104. },
  105. dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
  106. ;
  107. if($.fn.dimmer === undefined) {
  108. module.error(error.dimmer);
  109. return;
  110. }
  111. module.debug('Creating dimmer');
  112. $dimmable = $context.dimmer(dimmerSettings);
  113. if(settings.detachable) {
  114. module.verbose('Modal is detachable, moving content into dimmer');
  115. $dimmable.dimmer('add content', $module);
  116. }
  117. else {
  118. module.set.undetached();
  119. }
  120. $dimmer = $dimmable.dimmer('get dimmer');
  121. },
  122. id: function() {
  123. id = (Math.random().toString(16) + '000000000').substr(2, 8);
  124. elementEventNamespace = '.' + id;
  125. module.verbose('Creating unique id for element', id);
  126. },
  127. innerDimmer: function() {
  128. if ( $module.find(selector.dimmer).length == 0 ) {
  129. $module.prepend('<div class="ui inverted dimmer"></div>');
  130. }
  131. }
  132. },
  133. destroy: function() {
  134. if (observer) {
  135. observer.disconnect();
  136. }
  137. module.verbose('Destroying previous modal');
  138. $module
  139. .removeData(moduleNamespace)
  140. .off(eventNamespace)
  141. ;
  142. $window.off(elementEventNamespace);
  143. $dimmer.off(elementEventNamespace);
  144. $close.off(eventNamespace);
  145. $context.dimmer('destroy');
  146. },
  147. observeChanges: function() {
  148. if('MutationObserver' in window) {
  149. observer = new MutationObserver(function(mutations) {
  150. module.debug('DOM tree modified, refreshing');
  151. module.refresh();
  152. });
  153. observer.observe(element, {
  154. childList : true,
  155. subtree : true
  156. });
  157. module.debug('Setting up mutation observer', observer);
  158. }
  159. },
  160. refresh: function() {
  161. module.remove.scrolling();
  162. module.cacheSizes();
  163. if(!module.can.useFlex()) {
  164. module.set.modalOffset();
  165. }
  166. module.set.screenHeight();
  167. module.set.type();
  168. },
  169. refreshModals: function() {
  170. $otherModals = $module.siblings(selector.modal);
  171. $allModals = $otherModals.add($module);
  172. },
  173. attachEvents: function(selector, event) {
  174. var
  175. $toggle = $(selector)
  176. ;
  177. event = $.isFunction(module[event])
  178. ? module[event]
  179. : module.toggle
  180. ;
  181. if($toggle.length > 0) {
  182. module.debug('Attaching modal events to element', selector, event);
  183. $toggle
  184. .off(eventNamespace)
  185. .on('click' + eventNamespace, event)
  186. ;
  187. }
  188. else {
  189. module.error(error.notFound, selector);
  190. }
  191. },
  192. bind: {
  193. events: function() {
  194. module.verbose('Attaching events');
  195. $module
  196. .on('click' + eventNamespace, selector.close, module.event.close)
  197. .on('click' + eventNamespace, selector.approve, module.event.approve)
  198. .on('click' + eventNamespace, selector.deny, module.event.deny)
  199. ;
  200. $window
  201. .on('resize' + elementEventNamespace, module.event.resize)
  202. ;
  203. },
  204. scrollLock: function() {
  205. // touch events default to passive, due to changes in chrome to optimize mobile perf
  206. $dimmable.get(0).addEventListener('touchmove', module.event.preventScroll, { passive: false });
  207. }
  208. },
  209. unbind: {
  210. scrollLock: function() {
  211. $dimmable.get(0).removeEventListener('touchmove', module.event.preventScroll, { passive: false });
  212. }
  213. },
  214. get: {
  215. id: function() {
  216. return (Math.random().toString(16) + '000000000').substr(2, 8);
  217. }
  218. },
  219. event: {
  220. approve: function() {
  221. if(ignoreRepeatedEvents || settings.onApprove.call(element, $(this)) === false) {
  222. module.verbose('Approve callback returned false cancelling hide');
  223. return;
  224. }
  225. ignoreRepeatedEvents = true;
  226. module.hide(function() {
  227. ignoreRepeatedEvents = false;
  228. });
  229. },
  230. preventScroll: function(event) {
  231. if(event.target.className.indexOf('dimmer') !== -1) {
  232. event.preventDefault();
  233. }
  234. },
  235. deny: function() {
  236. if(ignoreRepeatedEvents || settings.onDeny.call(element, $(this)) === false) {
  237. module.verbose('Deny callback returned false cancelling hide');
  238. return;
  239. }
  240. ignoreRepeatedEvents = true;
  241. module.hide(function() {
  242. ignoreRepeatedEvents = false;
  243. });
  244. },
  245. close: function() {
  246. module.hide();
  247. },
  248. mousedown: function(event) {
  249. var
  250. $target = $(event.target),
  251. isRtl = module.is.rtl();
  252. ;
  253. initialMouseDownInModal = ($target.closest(selector.modal).length > 0);
  254. if(initialMouseDownInModal) {
  255. module.verbose('Mouse down event registered inside the modal');
  256. }
  257. initialMouseDownInScrollbar = module.is.scrolling() && ((!isRtl && $(window).outerWidth() - settings.scrollbarWidth <= event.clientX) || (isRtl && settings.scrollbarWidth >= event.clientX));
  258. if(initialMouseDownInScrollbar) {
  259. module.verbose('Mouse down event registered inside the scrollbar');
  260. }
  261. },
  262. mouseup: function(event) {
  263. if(!settings.closable) {
  264. module.verbose('Dimmer clicked but closable setting is disabled');
  265. return;
  266. }
  267. if(initialMouseDownInModal) {
  268. module.debug('Dimmer clicked but mouse down was initially registered inside the modal');
  269. return;
  270. }
  271. if(initialMouseDownInScrollbar){
  272. module.debug('Dimmer clicked but mouse down was initially registered inside the scrollbar');
  273. return;
  274. }
  275. var
  276. $target = $(event.target),
  277. isInModal = ($target.closest(selector.modal).length > 0),
  278. isInDOM = $.contains(document.documentElement, event.target)
  279. ;
  280. if(!isInModal && isInDOM && module.is.active() && $module.hasClass(className.front) ) {
  281. module.debug('Dimmer clicked, hiding all modals');
  282. if(settings.allowMultiple) {
  283. if(!module.hideAll()) {
  284. return;
  285. }
  286. }
  287. else if(!module.hide()){
  288. return;
  289. }
  290. module.remove.clickaway();
  291. }
  292. },
  293. debounce: function(method, delay) {
  294. clearTimeout(module.timer);
  295. module.timer = setTimeout(method, delay);
  296. },
  297. keyboard: function(event) {
  298. var
  299. keyCode = event.which,
  300. escapeKey = 27
  301. ;
  302. if(keyCode == escapeKey) {
  303. if(settings.closable) {
  304. module.debug('Escape key pressed hiding modal');
  305. if ( $module.hasClass(className.front) ) {
  306. module.hide();
  307. }
  308. }
  309. else {
  310. module.debug('Escape key pressed, but closable is set to false');
  311. }
  312. event.preventDefault();
  313. }
  314. },
  315. resize: function() {
  316. if( $dimmable.dimmer('is active') && ( module.is.animating() || module.is.active() ) ) {
  317. requestAnimationFrame(module.refresh);
  318. }
  319. }
  320. },
  321. toggle: function() {
  322. if( module.is.active() || module.is.animating() ) {
  323. module.hide();
  324. }
  325. else {
  326. module.show();
  327. }
  328. },
  329. show: function(callback) {
  330. callback = $.isFunction(callback)
  331. ? callback
  332. : function(){}
  333. ;
  334. module.refreshModals();
  335. module.set.dimmerSettings();
  336. module.set.dimmerStyles();
  337. module.showModal(callback);
  338. },
  339. hide: function(callback) {
  340. callback = $.isFunction(callback)
  341. ? callback
  342. : function(){}
  343. ;
  344. module.refreshModals();
  345. return module.hideModal(callback);
  346. },
  347. showModal: function(callback) {
  348. callback = $.isFunction(callback)
  349. ? callback
  350. : function(){}
  351. ;
  352. if( module.is.animating() || !module.is.active() ) {
  353. module.showDimmer();
  354. module.cacheSizes();
  355. module.set.bodyMargin();
  356. if(module.can.useFlex()) {
  357. module.remove.legacy();
  358. }
  359. else {
  360. module.set.legacy();
  361. module.set.modalOffset();
  362. module.debug('Using non-flex legacy modal positioning.');
  363. }
  364. module.set.screenHeight();
  365. module.set.type();
  366. module.set.clickaway();
  367. if( !settings.allowMultiple && module.others.active() ) {
  368. module.hideOthers(module.showModal);
  369. }
  370. else {
  371. ignoreRepeatedEvents = false;
  372. if( settings.allowMultiple ) {
  373. if ( module.others.active() ) {
  374. $otherModals.filter('.' + className.active).find(selector.dimmer).addClass('active');
  375. }
  376. if ( settings.detachable ) {
  377. $module.detach().appendTo($dimmer);
  378. }
  379. }
  380. settings.onShow.call(element);
  381. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  382. module.debug('Showing modal with css animations');
  383. $module
  384. .transition({
  385. debug : settings.debug,
  386. animation : settings.transition + ' in',
  387. queue : settings.queue,
  388. duration : settings.duration,
  389. useFailSafe : true,
  390. onComplete : function() {
  391. settings.onVisible.apply(element);
  392. if(settings.keyboardShortcuts) {
  393. module.add.keyboardShortcuts();
  394. }
  395. module.save.focus();
  396. module.set.active();
  397. if(settings.autofocus) {
  398. module.set.autofocus();
  399. }
  400. callback();
  401. }
  402. })
  403. ;
  404. }
  405. else {
  406. module.error(error.noTransition);
  407. }
  408. }
  409. }
  410. else {
  411. module.debug('Modal is already visible');
  412. }
  413. },
  414. hideModal: function(callback, keepDimmed, hideOthersToo) {
  415. var
  416. $previousModal = $otherModals.filter('.' + className.active).last()
  417. ;
  418. callback = $.isFunction(callback)
  419. ? callback
  420. : function(){}
  421. ;
  422. module.debug('Hiding modal');
  423. if(settings.onHide.call(element, $(this)) === false) {
  424. module.verbose('Hide callback returned false cancelling hide');
  425. ignoreRepeatedEvents = false;
  426. return false;
  427. }
  428. $module.fomanticExt.onModalBeforeHidden.call(element); // GITEA-PATCH: handle more UI updates before hidden
  429. if( module.is.animating() || module.is.active() ) {
  430. if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
  431. module.remove.active();
  432. $module
  433. .transition({
  434. debug : settings.debug,
  435. animation : settings.transition + ' out',
  436. queue : settings.queue,
  437. duration : settings.duration,
  438. useFailSafe : true,
  439. onStart : function() {
  440. if(!module.others.active() && !module.others.animating() && !keepDimmed) {
  441. module.hideDimmer();
  442. }
  443. if( settings.keyboardShortcuts && !module.others.active() ) {
  444. module.remove.keyboardShortcuts();
  445. }
  446. },
  447. onComplete : function() {
  448. module.unbind.scrollLock();
  449. if ( settings.allowMultiple ) {
  450. $previousModal.addClass(className.front);
  451. $module.removeClass(className.front);
  452. if ( hideOthersToo ) {
  453. $allModals.find(selector.dimmer).removeClass('active');
  454. }
  455. else {
  456. $previousModal.find(selector.dimmer).removeClass('active');
  457. }
  458. }
  459. settings.onHidden.call(element);
  460. module.remove.dimmerStyles();
  461. module.restore.focus();
  462. callback();
  463. }
  464. })
  465. ;
  466. }
  467. else {
  468. module.error(error.noTransition);
  469. }
  470. }
  471. },
  472. showDimmer: function() {
  473. if($dimmable.dimmer('is animating') || !$dimmable.dimmer('is active') ) {
  474. module.save.bodyMargin();
  475. module.debug('Showing dimmer');
  476. $dimmable.dimmer('show');
  477. }
  478. else {
  479. module.debug('Dimmer already visible');
  480. }
  481. },
  482. hideDimmer: function() {
  483. if( $dimmable.dimmer('is animating') || ($dimmable.dimmer('is active')) ) {
  484. module.unbind.scrollLock();
  485. $dimmable.dimmer('hide', function() {
  486. module.restore.bodyMargin();
  487. module.remove.clickaway();
  488. module.remove.screenHeight();
  489. });
  490. }
  491. else {
  492. module.debug('Dimmer is not visible cannot hide');
  493. return;
  494. }
  495. },
  496. hideAll: function(callback) {
  497. var
  498. $visibleModals = $allModals.filter('.' + className.active + ', .' + className.animating)
  499. ;
  500. callback = $.isFunction(callback)
  501. ? callback
  502. : function(){}
  503. ;
  504. if( $visibleModals.length > 0 ) {
  505. module.debug('Hiding all visible modals');
  506. var hideOk = true;
  507. //check in reverse order trying to hide most top displayed modal first
  508. $($visibleModals.get().reverse()).each(function(index,element){
  509. if(hideOk){
  510. hideOk = $(element).modal('hide modal', callback, false, true);
  511. }
  512. });
  513. if(hideOk) {
  514. module.hideDimmer();
  515. }
  516. return hideOk;
  517. }
  518. },
  519. hideOthers: function(callback) {
  520. var
  521. $visibleModals = $otherModals.filter('.' + className.active + ', .' + className.animating)
  522. ;
  523. callback = $.isFunction(callback)
  524. ? callback
  525. : function(){}
  526. ;
  527. if( $visibleModals.length > 0 ) {
  528. module.debug('Hiding other modals', $otherModals);
  529. $visibleModals
  530. .modal('hide modal', callback, true)
  531. ;
  532. }
  533. },
  534. others: {
  535. active: function() {
  536. return ($otherModals.filter('.' + className.active).length > 0);
  537. },
  538. animating: function() {
  539. return ($otherModals.filter('.' + className.animating).length > 0);
  540. }
  541. },
  542. add: {
  543. keyboardShortcuts: function() {
  544. module.verbose('Adding keyboard shortcuts');
  545. $document
  546. .on('keyup' + eventNamespace, module.event.keyboard)
  547. ;
  548. }
  549. },
  550. save: {
  551. focus: function() {
  552. var
  553. $activeElement = $(document.activeElement),
  554. inCurrentModal = $activeElement.closest($module).length > 0
  555. ;
  556. if(!inCurrentModal) {
  557. $focusedElement = $(document.activeElement).blur();
  558. }
  559. },
  560. bodyMargin: function() {
  561. initialBodyMargin = $body.css('margin-'+(module.can.leftBodyScrollbar() ? 'left':'right'));
  562. var bodyMarginRightPixel = parseInt(initialBodyMargin.replace(/[^\d.]/g, '')),
  563. bodyScrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
  564. tempBodyMargin = bodyMarginRightPixel + bodyScrollbarWidth;
  565. }
  566. },
  567. restore: {
  568. focus: function() {
  569. if($focusedElement && $focusedElement.length > 0 && settings.restoreFocus) {
  570. $focusedElement.focus();
  571. }
  572. },
  573. bodyMargin: function() {
  574. var position = module.can.leftBodyScrollbar() ? 'left':'right';
  575. $body.css('margin-'+position, initialBodyMargin);
  576. $body.find(selector.bodyFixed.replace('right',position)).css('padding-'+position, initialBodyMargin);
  577. }
  578. },
  579. remove: {
  580. active: function() {
  581. $module.removeClass(className.active);
  582. },
  583. legacy: function() {
  584. $module.removeClass(className.legacy);
  585. },
  586. clickaway: function() {
  587. if (!settings.detachable) {
  588. $module
  589. .off('mousedown' + elementEventNamespace)
  590. ;
  591. }
  592. $dimmer
  593. .off('mousedown' + elementEventNamespace)
  594. ;
  595. $dimmer
  596. .off('mouseup' + elementEventNamespace)
  597. ;
  598. },
  599. dimmerStyles: function() {
  600. $dimmer.removeClass(className.inverted);
  601. $dimmable.removeClass(className.blurring);
  602. },
  603. bodyStyle: function() {
  604. if($body.attr('style') === '') {
  605. module.verbose('Removing style attribute');
  606. $body.removeAttr('style');
  607. }
  608. },
  609. screenHeight: function() {
  610. module.debug('Removing page height');
  611. $body
  612. .css('height', '')
  613. ;
  614. },
  615. keyboardShortcuts: function() {
  616. module.verbose('Removing keyboard shortcuts');
  617. $document
  618. .off('keyup' + eventNamespace)
  619. ;
  620. },
  621. scrolling: function() {
  622. $dimmable.removeClass(className.scrolling);
  623. $module.removeClass(className.scrolling);
  624. }
  625. },
  626. cacheSizes: function() {
  627. $module.addClass(className.loading);
  628. var
  629. scrollHeight = $module.prop('scrollHeight'),
  630. modalWidth = $module.outerWidth(),
  631. modalHeight = $module.outerHeight()
  632. ;
  633. if(module.cache.pageHeight === undefined || modalHeight !== 0) {
  634. $.extend(module.cache, {
  635. pageHeight : $(document).outerHeight(),
  636. width : modalWidth,
  637. height : modalHeight + settings.offset,
  638. scrollHeight : scrollHeight + settings.offset,
  639. contextHeight : (settings.context == 'body')
  640. ? $(window).height()
  641. : $dimmable.height(),
  642. });
  643. module.cache.topOffset = -(module.cache.height / 2);
  644. }
  645. $module.removeClass(className.loading);
  646. module.debug('Caching modal and container sizes', module.cache);
  647. },
  648. can: {
  649. leftBodyScrollbar: function(){
  650. if(module.cache.leftBodyScrollbar === undefined) {
  651. module.cache.leftBodyScrollbar = module.is.rtl() && ((module.is.iframe && !module.is.firefox()) || module.is.safari() || module.is.edge() || module.is.ie());
  652. }
  653. return module.cache.leftBodyScrollbar;
  654. },
  655. useFlex: function() {
  656. if (settings.useFlex === 'auto') {
  657. return settings.detachable && !module.is.ie();
  658. }
  659. if(settings.useFlex && module.is.ie()) {
  660. module.debug('useFlex true is not supported in IE');
  661. } else if(settings.useFlex && !settings.detachable) {
  662. module.debug('useFlex true in combination with detachable false is not supported');
  663. }
  664. return settings.useFlex;
  665. },
  666. fit: function() {
  667. var
  668. contextHeight = module.cache.contextHeight,
  669. verticalCenter = module.cache.contextHeight / 2,
  670. topOffset = module.cache.topOffset,
  671. scrollHeight = module.cache.scrollHeight,
  672. height = module.cache.height,
  673. paddingHeight = settings.padding,
  674. startPosition = (verticalCenter + topOffset)
  675. ;
  676. return (scrollHeight > height)
  677. ? (startPosition + scrollHeight + paddingHeight < contextHeight)
  678. : (height + (paddingHeight * 2) < contextHeight)
  679. ;
  680. }
  681. },
  682. is: {
  683. active: function() {
  684. return $module.hasClass(className.active);
  685. },
  686. ie: function() {
  687. if(module.cache.isIE === undefined) {
  688. var
  689. isIE11 = (!(window.ActiveXObject) && 'ActiveXObject' in window),
  690. isIE = ('ActiveXObject' in window)
  691. ;
  692. module.cache.isIE = (isIE11 || isIE);
  693. }
  694. return module.cache.isIE;
  695. },
  696. animating: function() {
  697. return $module.transition('is supported')
  698. ? $module.transition('is animating')
  699. : $module.is(':visible')
  700. ;
  701. },
  702. scrolling: function() {
  703. return $dimmable.hasClass(className.scrolling);
  704. },
  705. modernBrowser: function() {
  706. // appName for IE11 reports 'Netscape' can no longer use
  707. return !(window.ActiveXObject || 'ActiveXObject' in window);
  708. },
  709. rtl: function() {
  710. if(module.cache.isRTL === undefined) {
  711. module.cache.isRTL = $body.attr('dir') === 'rtl' || $body.css('direction') === 'rtl';
  712. }
  713. return module.cache.isRTL;
  714. },
  715. safari: function() {
  716. if(module.cache.isSafari === undefined) {
  717. module.cache.isSafari = /constructor/i.test(window.HTMLElement) || !!window.ApplePaySession;
  718. }
  719. return module.cache.isSafari;
  720. },
  721. edge: function(){
  722. if(module.cache.isEdge === undefined) {
  723. module.cache.isEdge = !!window.setImmediate && !module.is.ie();
  724. }
  725. return module.cache.isEdge;
  726. },
  727. firefox: function(){
  728. if(module.cache.isFirefox === undefined) {
  729. module.cache.isFirefox = !!window.InstallTrigger;
  730. }
  731. return module.cache.isFirefox;
  732. },
  733. iframe: function() {
  734. return !(self === top);
  735. }
  736. },
  737. set: {
  738. autofocus: function() {
  739. var
  740. $inputs = $module.find('[tabindex], :input').filter(':visible').filter(function() {
  741. return $(this).closest('.disabled').length === 0;
  742. }),
  743. $autofocus = $inputs.filter('[autofocus]'),
  744. $input = ($autofocus.length > 0)
  745. ? $autofocus.first()
  746. : $inputs.first()
  747. ;
  748. if($input.length > 0) {
  749. $input.focus();
  750. }
  751. },
  752. bodyMargin: function() {
  753. var position = module.can.leftBodyScrollbar() ? 'left':'right';
  754. if(settings.detachable || module.can.fit()) {
  755. $body.css('margin-'+position, tempBodyMargin + 'px');
  756. }
  757. $body.find(selector.bodyFixed.replace('right',position)).css('padding-'+position, tempBodyMargin + 'px');
  758. },
  759. clickaway: function() {
  760. if (!settings.detachable) {
  761. $module
  762. .on('mousedown' + elementEventNamespace, module.event.mousedown)
  763. ;
  764. }
  765. $dimmer
  766. .on('mousedown' + elementEventNamespace, module.event.mousedown)
  767. ;
  768. $dimmer
  769. .on('mouseup' + elementEventNamespace, module.event.mouseup)
  770. ;
  771. },
  772. dimmerSettings: function() {
  773. if($.fn.dimmer === undefined) {
  774. module.error(error.dimmer);
  775. return;
  776. }
  777. var
  778. defaultSettings = {
  779. debug : settings.debug,
  780. dimmerName : 'modals',
  781. closable : 'auto',
  782. useFlex : module.can.useFlex(),
  783. duration : {
  784. show : settings.duration,
  785. hide : settings.duration
  786. }
  787. },
  788. dimmerSettings = $.extend(true, defaultSettings, settings.dimmerSettings)
  789. ;
  790. if(settings.inverted) {
  791. dimmerSettings.variation = (dimmerSettings.variation !== undefined)
  792. ? dimmerSettings.variation + ' inverted'
  793. : 'inverted'
  794. ;
  795. }
  796. $context.dimmer('setting', dimmerSettings);
  797. },
  798. dimmerStyles: function() {
  799. if(settings.inverted) {
  800. $dimmer.addClass(className.inverted);
  801. }
  802. else {
  803. $dimmer.removeClass(className.inverted);
  804. }
  805. if(settings.blurring) {
  806. $dimmable.addClass(className.blurring);
  807. }
  808. else {
  809. $dimmable.removeClass(className.blurring);
  810. }
  811. },
  812. modalOffset: function() {
  813. if (!settings.detachable) {
  814. var canFit = module.can.fit();
  815. $module
  816. .css({
  817. top: (!$module.hasClass('aligned') && canFit)
  818. ? $(document).scrollTop() + (module.cache.contextHeight - module.cache.height) / 2
  819. : !canFit || $module.hasClass('top')
  820. ? $(document).scrollTop() + settings.padding
  821. : $(document).scrollTop() + (module.cache.contextHeight - module.cache.height - settings.padding),
  822. marginLeft: -(module.cache.width / 2)
  823. })
  824. ;
  825. } else {
  826. $module
  827. .css({
  828. marginTop: (!$module.hasClass('aligned') && module.can.fit())
  829. ? -(module.cache.height / 2)
  830. : settings.padding / 2,
  831. marginLeft: -(module.cache.width / 2)
  832. })
  833. ;
  834. }
  835. module.verbose('Setting modal offset for legacy mode');
  836. },
  837. screenHeight: function() {
  838. if( module.can.fit() ) {
  839. $body.css('height', '');
  840. }
  841. else if(!$module.hasClass('bottom')) {
  842. module.debug('Modal is taller than page content, resizing page height');
  843. $body
  844. .css('height', module.cache.height + (settings.padding * 2) )
  845. ;
  846. }
  847. },
  848. active: function() {
  849. $module.addClass(className.active + ' ' + className.front);
  850. $otherModals.filter('.' + className.active).removeClass(className.front);
  851. },
  852. scrolling: function() {
  853. $dimmable.addClass(className.scrolling);
  854. $module.addClass(className.scrolling);
  855. module.unbind.scrollLock();
  856. },
  857. legacy: function() {
  858. $module.addClass(className.legacy);
  859. },
  860. type: function() {
  861. if(module.can.fit()) {
  862. module.verbose('Modal fits on screen');
  863. if(!module.others.active() && !module.others.animating()) {
  864. module.remove.scrolling();
  865. module.bind.scrollLock();
  866. }
  867. }
  868. else if (!$module.hasClass('bottom')){
  869. module.verbose('Modal cannot fit on screen setting to scrolling');
  870. module.set.scrolling();
  871. } else {
  872. module.verbose('Bottom aligned modal not fitting on screen is unsupported for scrolling');
  873. }
  874. },
  875. undetached: function() {
  876. $dimmable.addClass(className.undetached);
  877. }
  878. },
  879. setting: function(name, value) {
  880. module.debug('Changing setting', name, value);
  881. if( $.isPlainObject(name) ) {
  882. $.extend(true, settings, name);
  883. }
  884. else if(value !== undefined) {
  885. if($.isPlainObject(settings[name])) {
  886. $.extend(true, settings[name], value);
  887. }
  888. else {
  889. settings[name] = value;
  890. }
  891. }
  892. else {
  893. return settings[name];
  894. }
  895. },
  896. internal: function(name, value) {
  897. if( $.isPlainObject(name) ) {
  898. $.extend(true, module, name);
  899. }
  900. else if(value !== undefined) {
  901. module[name] = value;
  902. }
  903. else {
  904. return module[name];
  905. }
  906. },
  907. debug: function() {
  908. if(!settings.silent && settings.debug) {
  909. if(settings.performance) {
  910. module.performance.log(arguments);
  911. }
  912. else {
  913. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  914. module.debug.apply(console, arguments);
  915. }
  916. }
  917. },
  918. verbose: function() {
  919. if(!settings.silent && settings.verbose && settings.debug) {
  920. if(settings.performance) {
  921. module.performance.log(arguments);
  922. }
  923. else {
  924. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  925. module.verbose.apply(console, arguments);
  926. }
  927. }
  928. },
  929. error: function() {
  930. if(!settings.silent) {
  931. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  932. module.error.apply(console, arguments);
  933. }
  934. },
  935. performance: {
  936. log: function(message) {
  937. var
  938. currentTime,
  939. executionTime,
  940. previousTime
  941. ;
  942. if(settings.performance) {
  943. currentTime = new Date().getTime();
  944. previousTime = time || currentTime;
  945. executionTime = currentTime - previousTime;
  946. time = currentTime;
  947. performance.push({
  948. 'Name' : message[0],
  949. 'Arguments' : [].slice.call(message, 1) || '',
  950. 'Element' : element,
  951. 'Execution Time' : executionTime
  952. });
  953. }
  954. clearTimeout(module.performance.timer);
  955. module.performance.timer = setTimeout(module.performance.display, 500);
  956. },
  957. display: function() {
  958. var
  959. title = settings.name + ':',
  960. totalTime = 0
  961. ;
  962. time = false;
  963. clearTimeout(module.performance.timer);
  964. $.each(performance, function(index, data) {
  965. totalTime += data['Execution Time'];
  966. });
  967. title += ' ' + totalTime + 'ms';
  968. if(moduleSelector) {
  969. title += ' \'' + moduleSelector + '\'';
  970. }
  971. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  972. console.groupCollapsed(title);
  973. if(console.table) {
  974. console.table(performance);
  975. }
  976. else {
  977. $.each(performance, function(index, data) {
  978. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  979. });
  980. }
  981. console.groupEnd();
  982. }
  983. performance = [];
  984. }
  985. },
  986. invoke: function(query, passedArguments, context) {
  987. var
  988. object = instance,
  989. maxDepth,
  990. found,
  991. response
  992. ;
  993. passedArguments = passedArguments || queryArguments;
  994. context = element || context;
  995. if(typeof query == 'string' && object !== undefined) {
  996. query = query.split(/[\. ]/);
  997. maxDepth = query.length - 1;
  998. $.each(query, function(depth, value) {
  999. var camelCaseValue = (depth != maxDepth)
  1000. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  1001. : query
  1002. ;
  1003. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  1004. object = object[camelCaseValue];
  1005. }
  1006. else if( object[camelCaseValue] !== undefined ) {
  1007. found = object[camelCaseValue];
  1008. return false;
  1009. }
  1010. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  1011. object = object[value];
  1012. }
  1013. else if( object[value] !== undefined ) {
  1014. found = object[value];
  1015. return false;
  1016. }
  1017. else {
  1018. return false;
  1019. }
  1020. });
  1021. }
  1022. if ( $.isFunction( found ) ) {
  1023. response = found.apply(context, passedArguments);
  1024. }
  1025. else if(found !== undefined) {
  1026. response = found;
  1027. }
  1028. if(Array.isArray(returnedValue)) {
  1029. returnedValue.push(response);
  1030. }
  1031. else if(returnedValue !== undefined) {
  1032. returnedValue = [returnedValue, response];
  1033. }
  1034. else if(response !== undefined) {
  1035. returnedValue = response;
  1036. }
  1037. return found;
  1038. }
  1039. };
  1040. if(methodInvoked) {
  1041. if(instance === undefined) {
  1042. module.initialize();
  1043. }
  1044. module.invoke(query);
  1045. }
  1046. else {
  1047. if(instance !== undefined) {
  1048. instance.invoke('destroy');
  1049. }
  1050. module.initialize();
  1051. }
  1052. })
  1053. ;
  1054. return (returnedValue !== undefined)
  1055. ? returnedValue
  1056. : this
  1057. ;
  1058. };
  1059. $.fn.modal.settings = {
  1060. name : 'Modal',
  1061. namespace : 'modal',
  1062. useFlex : 'auto',
  1063. offset : 0,
  1064. silent : false,
  1065. debug : false,
  1066. verbose : false,
  1067. performance : true,
  1068. observeChanges : false,
  1069. allowMultiple : false,
  1070. detachable : true,
  1071. closable : true,
  1072. autofocus : true,
  1073. restoreFocus : true,
  1074. inverted : false,
  1075. blurring : false,
  1076. centered : true,
  1077. dimmerSettings : {
  1078. closable : false,
  1079. useCSS : true
  1080. },
  1081. // whether to use keyboard shortcuts
  1082. keyboardShortcuts: true,
  1083. context : 'body',
  1084. queue : false,
  1085. duration : 500,
  1086. transition : 'scale',
  1087. // padding with edge of page
  1088. padding : 50,
  1089. scrollbarWidth: 10,
  1090. // called before show animation
  1091. onShow : function(){},
  1092. // called after show animation
  1093. onVisible : function(){},
  1094. // called before hide animation
  1095. onHide : function(){ return true; },
  1096. // called after hide animation
  1097. onHidden : function(){},
  1098. // called after approve selector match
  1099. onApprove : function(){ return true; },
  1100. // called after deny selector match
  1101. onDeny : function(){ return true; },
  1102. selector : {
  1103. close : '> .close',
  1104. approve : '.actions .positive, .actions .approve, .actions .ok',
  1105. deny : '.actions .negative, .actions .deny, .actions .cancel',
  1106. modal : '.ui.modal',
  1107. dimmer : '> .ui.dimmer',
  1108. bodyFixed: '> .ui.fixed.menu, > .ui.right.toast-container, > .ui.right.sidebar'
  1109. },
  1110. error : {
  1111. dimmer : 'UI Dimmer, a required component is not included in this page',
  1112. method : 'The method you called is not defined.',
  1113. notFound : 'The element you specified could not be found'
  1114. },
  1115. className : {
  1116. active : 'active',
  1117. animating : 'animating',
  1118. blurring : 'blurring',
  1119. inverted : 'inverted',
  1120. legacy : 'legacy',
  1121. loading : 'loading',
  1122. scrolling : 'scrolling',
  1123. undetached : 'undetached',
  1124. front : 'front'
  1125. }
  1126. };
  1127. })( jQuery, window, document );