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.

478 lines
13 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. /*
  2. * # Semantic - Modal
  3. * http://github.com/jlukic/semantic-ui/
  4. *
  5. *
  6. * Copyright 2013 Contributors
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ( $, window, document, undefined ) {
  12. $.fn.modal = function(parameters) {
  13. var
  14. $allModals = $(this),
  15. $document = $(document),
  16. settings = ( $.isPlainObject(parameters) )
  17. ? $.extend(true, {}, $.fn.modal.settings, parameters)
  18. : $.fn.modal.settings,
  19. selector = settings.selector,
  20. className = settings.className,
  21. namespace = settings.namespace,
  22. error = settings.error,
  23. eventNamespace = '.' + namespace,
  24. moduleNamespace = 'module-' + namespace,
  25. moduleSelector = $allModals.selector || '',
  26. time = new Date().getTime(),
  27. performance = [],
  28. query = arguments[0],
  29. methodInvoked = (typeof query == 'string'),
  30. queryArguments = [].slice.call(arguments, 1),
  31. invokedResponse
  32. ;
  33. $allModals
  34. .each(function() {
  35. var
  36. $modal = $(this),
  37. $context = $(settings.context),
  38. $otherModals = $allModals.not($modal),
  39. $closeButton = $modal.find(selector.closeButton),
  40. $dimmer,
  41. element = this,
  42. instance = $modal.data(moduleNamespace),
  43. modal
  44. ;
  45. modal = {
  46. initialize: function() {
  47. modal.verbose('Attaching events');
  48. $closeButton
  49. .on('click', modal.event.close)
  50. ;
  51. modal.cache.sizes();
  52. modal.verbose('Creating dimmer');
  53. $context
  54. .dimmer({
  55. closable: settings.closable,
  56. duration: settings.duration,
  57. onShow: function() {
  58. modal.add.keyboardShortcuts();
  59. $.proxy(settings.onShow, this)();
  60. },
  61. onHide: function() {
  62. if($modal.is(':visible')) {
  63. $context.off('.dimmer');
  64. modal.hide();
  65. $.proxy(settings.onHide, this)();
  66. }
  67. modal.remove.keyboardShortcuts();
  68. }
  69. })
  70. ;
  71. $dimmer = $context.children(selector.dimmer);
  72. if( $modal.parent()[0] !== $dimmer[0] ) {
  73. modal.debug('Moving element inside dimmer', $context);
  74. $modal = $modal
  75. .detach()
  76. .appendTo($dimmer)
  77. ;
  78. }
  79. modal.instantiate();
  80. },
  81. instantiate: function() {
  82. modal.verbose('Storing instance of modal');
  83. instance = modal;
  84. $modal
  85. .data(moduleNamespace, instance)
  86. ;
  87. },
  88. destroy: function() {
  89. modal.verbose('Destroying previous modal');
  90. $modal
  91. .off(eventNamespace)
  92. ;
  93. },
  94. event: {
  95. close: function() {
  96. modal.verbose('Close button pressed');
  97. $context.dimmer('hide');
  98. },
  99. keyboard: function(event) {
  100. var
  101. keyCode = event.which,
  102. escapeKey = 27
  103. ;
  104. if(keyCode == escapeKey) {
  105. modal.debug('Escape key pressed hiding modal');
  106. $context.dimmer('hide');
  107. event.preventDefault();
  108. }
  109. },
  110. resize: function() {
  111. modal.cache.sizes();
  112. if( $modal.is(':visible') ) {
  113. modal.set.type();
  114. modal.set.position();
  115. }
  116. }
  117. },
  118. toggle: function() {
  119. if( modal.is.active() ) {
  120. modal.hide();
  121. }
  122. else {
  123. modal.show();
  124. }
  125. },
  126. show: function() {
  127. modal.debug('Showing modal');
  128. modal.set.type();
  129. modal.set.position();
  130. modal.hideAll();
  131. if(settings.transition && $.fn.transition !== undefined) {
  132. $modal
  133. .transition(settings.transition + ' in', settings.duration, modal.set.active)
  134. ;
  135. }
  136. else {
  137. $modal
  138. .fadeIn(settings.duration, settings.easing, modal.set.active)
  139. ;
  140. }
  141. modal.debug('Triggering dimmer');
  142. $context.dimmer('show');
  143. },
  144. hide: function() {
  145. modal.debug('Hiding modal');
  146. // remove keyboard detection
  147. $document
  148. .off('keyup.' + namespace)
  149. ;
  150. if(settings.transition && $.fn.transition !== undefined) {
  151. $modal
  152. .transition(settings.transition + ' out', settings.duration, modal.remove.active)
  153. ;
  154. }
  155. else {
  156. $modal
  157. .fadeOut(settings.duration, settings.easing, modal.remove.active)
  158. ;
  159. }
  160. },
  161. hideAll: function() {
  162. $otherModals
  163. .filter(':visible')
  164. .modal('hide')
  165. ;
  166. },
  167. add: {
  168. keyboardShortcuts: function() {
  169. modal.verbose('Adding keyboard shortcuts');
  170. $document
  171. .on('keyup' + eventNamespace, modal.event.keyboard)
  172. ;
  173. }
  174. },
  175. remove: {
  176. active: function() {
  177. $modal.removeClass(className.active);
  178. },
  179. keyboardShortcuts: function() {
  180. modal.verbose('Removing keyboard shortcuts');
  181. $document
  182. .off('keyup' + eventNamespace)
  183. ;
  184. }
  185. },
  186. cache: {
  187. sizes: function() {
  188. modal.cache = {
  189. height : $modal.outerHeight() + settings.offset,
  190. contextHeight : (settings.context == 'body')
  191. ? $(window).height()
  192. : $context.height()
  193. };
  194. console.log($modal);
  195. modal.debug('Caching modal and container sizes', modal.cache);
  196. }
  197. },
  198. can: {
  199. fit: function() {
  200. return (modal.cache.height < modal.cache.contextHeight);
  201. }
  202. },
  203. is: {
  204. active: function() {
  205. return $modal.hasClass(className.active);
  206. }
  207. },
  208. set: {
  209. active: function() {
  210. $modal.addClass('active');
  211. },
  212. type: function() {
  213. if(modal.can.fit()) {
  214. modal.verbose('Modal fits on screen');
  215. $modal.removeClass(className.scrolling);
  216. }
  217. else {
  218. modal.verbose('Modal cannot fit on screen setting to scrolling');
  219. $modal.addClass(className.scrolling);
  220. }
  221. },
  222. position: function() {
  223. modal.verbose('Centering modal on page', modal.cache.height / 2);
  224. if(modal.can.fit()) {
  225. $modal
  226. .css({
  227. marginTop: -(modal.cache.height / 2)
  228. })
  229. ;
  230. }
  231. else {
  232. $modal
  233. .css({
  234. top: $context.prop('scrollTop')
  235. })
  236. ;
  237. }
  238. }
  239. },
  240. setting: function(name, value) {
  241. if(value !== undefined) {
  242. if( $.isPlainObject(name) ) {
  243. $.extend(true, settings, name);
  244. }
  245. else {
  246. settings[name] = value;
  247. }
  248. }
  249. else {
  250. return settings[name];
  251. }
  252. },
  253. internal: function(name, value) {
  254. if(value !== undefined) {
  255. if( $.isPlainObject(name) ) {
  256. $.extend(true, modal, name);
  257. }
  258. else {
  259. modal[name] = value;
  260. }
  261. }
  262. else {
  263. return modal[name];
  264. }
  265. },
  266. debug: function() {
  267. if(settings.debug) {
  268. if(settings.performance) {
  269. modal.performance.log(arguments);
  270. }
  271. else {
  272. modal.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  273. modal.debug.apply(console, arguments);
  274. }
  275. }
  276. },
  277. verbose: function() {
  278. if(settings.verbose && settings.debug) {
  279. if(settings.performance) {
  280. modal.performance.log(arguments);
  281. }
  282. else {
  283. modal.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  284. modal.verbose.apply(console, arguments);
  285. }
  286. }
  287. },
  288. error: function() {
  289. modal.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  290. modal.error.apply(console, arguments);
  291. },
  292. performance: {
  293. log: function(message) {
  294. var
  295. currentTime,
  296. executionTime,
  297. previousTime
  298. ;
  299. if(settings.performance) {
  300. currentTime = new Date().getTime();
  301. previousTime = time || currentTime;
  302. executionTime = currentTime - previousTime;
  303. time = currentTime;
  304. performance.push({
  305. 'Element' : element,
  306. 'Name' : message[0],
  307. 'Arguments' : [].slice.call(message, 1) || '',
  308. 'Execution Time' : executionTime
  309. });
  310. }
  311. clearTimeout(modal.performance.timer);
  312. modal.performance.timer = setTimeout(modal.performance.display, 100);
  313. },
  314. display: function() {
  315. var
  316. title = settings.name + ':',
  317. totalTime = 0
  318. ;
  319. time = false;
  320. clearTimeout(modal.performance.timer);
  321. $.each(performance, function(index, data) {
  322. totalTime += data['Execution Time'];
  323. });
  324. title += ' ' + totalTime + 'ms';
  325. if(moduleSelector) {
  326. title += ' \'' + moduleSelector + '\'';
  327. }
  328. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  329. console.groupCollapsed(title);
  330. if(console.table) {
  331. console.table(performance);
  332. }
  333. else {
  334. $.each(performance, function(index, data) {
  335. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  336. });
  337. }
  338. console.groupEnd();
  339. }
  340. performance = [];
  341. }
  342. },
  343. invoke: function(query, passedArguments, context) {
  344. var
  345. maxDepth,
  346. found,
  347. response
  348. ;
  349. passedArguments = passedArguments || queryArguments;
  350. context = element || context;
  351. if(typeof query == 'string' && instance !== undefined) {
  352. query = query.split(/[\. ]/);
  353. maxDepth = query.length - 1;
  354. $.each(query, function(depth, value) {
  355. var camelCaseValue = (depth != maxDepth)
  356. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  357. : query
  358. ;
  359. if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) {
  360. instance = instance[value];
  361. }
  362. else if( $.isPlainObject( instance[camelCaseValue] ) && (depth != maxDepth) ) {
  363. instance = instance[camelCaseValue];
  364. }
  365. else if( instance[value] !== undefined ) {
  366. found = instance[value];
  367. return false;
  368. }
  369. else if( instance[camelCaseValue] !== undefined ) {
  370. found = instance[camelCaseValue];
  371. return false;
  372. }
  373. else {
  374. modal.error(error.method);
  375. return false;
  376. }
  377. });
  378. }
  379. if ( $.isFunction( found ) ) {
  380. response = found.apply(context, passedArguments);
  381. }
  382. else if(found !== undefined) {
  383. response = found;
  384. }
  385. if($.isArray(invokedResponse)) {
  386. invokedResponse.push(response);
  387. }
  388. else if(typeof invokedResponse == 'string') {
  389. invokedResponse = [invokedResponse, response];
  390. }
  391. else if(response !== undefined) {
  392. invokedResponse = response;
  393. }
  394. return found;
  395. }
  396. };
  397. if(methodInvoked) {
  398. if(instance === undefined) {
  399. modal.initialize();
  400. }
  401. invokedResponse = modal.invoke(query);
  402. }
  403. else {
  404. if(instance !== undefined) {
  405. modal.destroy();
  406. }
  407. modal.initialize();
  408. }
  409. })
  410. ;
  411. return (invokedResponse !== undefined)
  412. ? invokedResponse
  413. : this
  414. ;
  415. };
  416. $.fn.modal.settings = {
  417. name : 'Modal',
  418. namespace : 'modal',
  419. verbose : true,
  420. debug : true,
  421. performance : true,
  422. offset : 0,
  423. transition : 'scale',
  424. duration : 500,
  425. easing : 'easeOutExpo',
  426. closable : true,
  427. context : 'body',
  428. onShow : function(){},
  429. onHide : function(){},
  430. selector : {
  431. closeButton : '.close, .actions .button',
  432. dimmer: '.ui.dimmer'
  433. },
  434. error : {
  435. method : 'The method you called is not defined.'
  436. },
  437. className : {
  438. scrolling : 'scrolling'
  439. },
  440. };
  441. })( jQuery, window , document );