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.

358 lines
10 KiB

  1. /* ******************************
  2. Modal
  3. Author: Jack Lukic
  4. Notes: First Commit May 14, 2012
  5. Manages modal state and
  6. stage dimming
  7. ****************************** */
  8. ;(function ( $, window, document, undefined ) {
  9. $.dimScreen = function(parameters) {
  10. var
  11. // if parameter is string it is callback function
  12. settings = (typeof parameters == 'function')
  13. ? $.extend({}, $.fn.modal.settings, { dim: parameters })
  14. : $.extend({}, $.fn.modal.settings, parameters),
  15. $context = $(settings.context),
  16. $dimmer = $context.children(settings.selector.dimmer),
  17. dimmerExists = ($dimmer.size() > 0),
  18. currentOpacity = $dimmer.css('opacity')
  19. ;
  20. if(!dimmerExists) {
  21. $dimmer = $('<div/>')
  22. .attr('id','dimmer')
  23. .html('<div class="content"></div>')
  24. ;
  25. $context
  26. .append($dimmer)
  27. ;
  28. }
  29. if(currentOpacity != settings.opacity) {
  30. $dimmer
  31. .one('click', function() {
  32. settings.unDim();
  33. $.unDimScreen();
  34. })
  35. ;
  36. if(settings.duration === 0) {
  37. $dimmer
  38. .css({
  39. visibility : 'visible'
  40. })
  41. .find('.content')
  42. .css({
  43. opacity : settings.opacity,
  44. visibility : 'visible'
  45. })
  46. ;
  47. settings.dim();
  48. }
  49. else {
  50. $dimmer
  51. .css({
  52. visibility : 'visible'
  53. })
  54. .find('.content')
  55. .css({
  56. opacity : 0,
  57. visibility : 'visible'
  58. })
  59. .fadeTo(settings.duration, settings.opacity, settings.dim)
  60. ;
  61. }
  62. }
  63. return this;
  64. };
  65. $.unDimScreen = function(parameters) {
  66. var
  67. settings = (typeof parameters == 'function')
  68. ? $.extend({}, $.fn.modal.settings, { unDim: parameters })
  69. : $.extend({}, $.fn.modal.settings, parameters),
  70. $context = $(settings.context),
  71. $dimmer = $context.children(settings.selector.dimmer),
  72. dimmerExists = ($dimmer.size() > 0)
  73. ;
  74. if(dimmerExists) {
  75. // callback before unDim
  76. settings.unDim();
  77. if(settings.duration === 0) {
  78. $dimmer
  79. .css({
  80. visibility: 'hidden'
  81. })
  82. .remove()
  83. ;
  84. }
  85. else {
  86. $dimmer
  87. .find('.content')
  88. .fadeTo(settings.duration, 0, function(){
  89. $dimmer.remove();
  90. })
  91. ;
  92. }
  93. }
  94. return this;
  95. };
  96. $.fn.modal = function(parameters) {
  97. var
  98. settings = $.extend(true, {}, $.fn.modal.settings, parameters),
  99. // make arguments available
  100. query = arguments[0],
  101. passedArguments = [].slice.call(arguments, 1),
  102. invokedResponse
  103. ;
  104. $(this)
  105. .each(function() {
  106. var
  107. $modal = $(this),
  108. $closeButton = $modal.find(settings.selector.closeButton),
  109. $dimmer = $(settings.context).find(settings.selector.dimmer),
  110. $modals = $(settings.context).children(settings.selector.modal),
  111. $otherModals = $modals.not($modal),
  112. instance = $modal.data('module-' + settings.namespace),
  113. methodInvoked = (typeof query == 'string'),
  114. className = settings.className,
  115. namespace = settings.namespace,
  116. module
  117. ;
  118. module = {
  119. initialize: function() {
  120. // attach events
  121. $modal
  122. .on('modalShow.' + namespace, module.show)
  123. .on('modalHide.' + namespace, module.hide)
  124. .data('module-' + namespace, module)
  125. ;
  126. },
  127. show: function() {
  128. var
  129. modalHeight = $modal.outerHeight(),
  130. windowHeight = $(window).height(),
  131. cantFit = (modalHeight > windowHeight),
  132. modalType = (cantFit)
  133. ? 'absolute'
  134. : 'fixed',
  135. topCentering = (cantFit)
  136. ? '0'
  137. : '50%',
  138. offsetTop = (cantFit)
  139. ? (windowHeight / 8)
  140. : -( (modalHeight - settings.closeSpacing) / 2),
  141. finalPosition = ($modal.css('position') == 'absolute')
  142. ? offsetTop + $(window).prop('pageYOffset')
  143. : offsetTop,
  144. startPosition = finalPosition + settings.animationOffset
  145. ;
  146. // set top margin as offset
  147. if($.fn.popIn !== undefined) {
  148. $modal
  149. .addClass(modalType)
  150. .css({
  151. display : 'block',
  152. opacity : 0,
  153. top: topCentering,
  154. marginTop : finalPosition + 'px'
  155. })
  156. .popIn()
  157. ;
  158. }
  159. else {
  160. $modal
  161. .addClass(modalType)
  162. .css({
  163. display : 'block',
  164. opacity : 0,
  165. top: topCentering,
  166. marginTop : startPosition + 'px'
  167. })
  168. .animate({
  169. opacity : 1,
  170. marginTop : finalPosition + 'px'
  171. }, (settings.duration + 300), settings.easing)
  172. ;
  173. }
  174. if( $otherModals.is(':visible') ) {
  175. $otherModals
  176. .filter(':visible')
  177. .hide()
  178. ;
  179. }
  180. console.log('zzz');
  181. $.dimScreen({
  182. context : settings.context,
  183. duration : 0,
  184. dim : function() {
  185. console.log('aaa');
  186. $(document)
  187. .on('keyup.' + namespace, function(event) {
  188. var
  189. keyCode = event.which,
  190. escapeKey = 27
  191. ;
  192. switch(keyCode) {
  193. case escapeKey:
  194. $modal.modal('hide');
  195. event.preventDefault();
  196. break;
  197. }
  198. })
  199. ;
  200. console.log($closeButton);
  201. console.log('attaching click');
  202. $closeButton
  203. .one('click', function() {
  204. $modal.modal('hide');
  205. })
  206. ;
  207. settings.dim();
  208. },
  209. unDim: function() {
  210. $modal.modal('hide');
  211. $closeButton.unbind('click');
  212. }
  213. });
  214. },
  215. hide: function() {
  216. // remove keyboard detection
  217. $(document)
  218. .off('keyup.' + namespace)
  219. ;
  220. $.unDimScreen({
  221. duration: 0,
  222. unDim: function() {
  223. $modal
  224. .popOut(200)
  225. ;
  226. settings.unDim();
  227. }
  228. });
  229. },
  230. /* standard module */
  231. setting: function(name, value) {
  232. if(value === undefined) {
  233. return settings[name];
  234. }
  235. settings[name] = value;
  236. },
  237. debug: function() {
  238. var
  239. output = [],
  240. message = settings.moduleName + ': ' + arguments[0],
  241. variables = [].slice.call( arguments, 1 ),
  242. log = console.info || console.log || function(){}
  243. ;
  244. if(settings.debug) {
  245. output.push(message);
  246. log.apply(console, output.concat(variables) );
  247. }
  248. },
  249. error: function() {
  250. var
  251. output = [],
  252. errorMessage = settings.moduleName + ': ' + arguments[0],
  253. variables = [].slice.call( arguments, 1 ),
  254. log = console.warn || console.log || function(){}
  255. ;
  256. if(settings.debug) {
  257. output.push(errorMessage);
  258. output.concat(variables);
  259. log.apply(console, output.concat(variables) );
  260. }
  261. },
  262. invoke: function(query, context, passedArguments) {
  263. var
  264. maxDepth,
  265. found
  266. ;
  267. passedArguments = passedArguments || [].slice.call( arguments, 2 );
  268. if(typeof query == 'string' && instance !== undefined) {
  269. query = query.split('.');
  270. maxDepth = query.length - 1;
  271. $.each(query, function(depth, value) {
  272. if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) {
  273. instance = instance[value];
  274. return true;
  275. }
  276. else if( instance[value] !== undefined ) {
  277. found = instance[value];
  278. return true;
  279. }
  280. module.error(settings.errors.method);
  281. return false;
  282. });
  283. }
  284. if ( $.isFunction( found ) ) {
  285. return found.apply(context, passedArguments);
  286. }
  287. // return retrieved variable or chain
  288. return found;
  289. }
  290. };
  291. // check for invoking internal method
  292. if(methodInvoked) {
  293. invokedResponse = module.invoke(query, this, passedArguments);
  294. }
  295. // otherwise initialize
  296. else {
  297. module.initialize();
  298. }
  299. })
  300. ;
  301. // chain or return queried method
  302. return (invokedResponse !== undefined)
  303. ? invokedResponse
  304. : this
  305. ;
  306. };
  307. $.fn.modal.settings = {
  308. moduleName : 'Modal',
  309. debug : false,
  310. namespace : 'modal',
  311. errors: {
  312. method : 'The method you called is not defined'
  313. },
  314. dim : function(){},
  315. unDim : function(){},
  316. hide : function(){},
  317. show : function(){},
  318. context : 'body',
  319. opacity : 0.8,
  320. closeSpacing : 25,
  321. animationOffset : 15,
  322. duration : 400,
  323. easing : 'easeOutExpo',
  324. selector : {
  325. dimmer : '#dimmer',
  326. modal : '.modal',
  327. closeButton : '.close'
  328. }
  329. };
  330. })( jQuery, window , document );