PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/prototype/dialogbox.js

https://github.com/okonet/dialogbox
JavaScript | 267 lines | 205 code | 32 blank | 30 comment | 41 complexity | 729813a51067c7abbcab347704e8cc78 MD5 | raw file
  1. //
  2. // dialogbox.js
  3. //
  4. // Created by Andrey Okonetchnikov on 2010-11-15.
  5. // Copyright 2010 Andrey Okonetchnikov. All rights reserved.
  6. //
  7. var DialogBox = {
  8. options: {},
  9. default_options: {
  10. 'width': 600,
  11. 'height': 400
  12. },
  13. initialize: function(options) {
  14. if(this.initialized) return this;
  15. this.loader = new Element('div', { 'className': 'dialogbox_loader', 'rel': 'dialogbox:close' });
  16. this.overlay = new Element('div', { 'className': 'dialogbox_overlay', 'rel': 'dialogbox:close' });
  17. this.box = new Element('div', { 'className': 'dialogbox_dialog' }).setStyle({'visibilty': 'hidden'});
  18. this.content = new Element('div', { 'className': 'dialogbox_dialog_content' });
  19. this.close = new Element('div', { 'className': 'dialogbox_close', 'rel': 'dialogbox:close' });
  20. this.box.insert(this.close);
  21. this.box.insert(this.content);
  22. $(document.body).insert(this.overlay);
  23. $(document.body).insert(this.box);
  24. $(document.body).insert(this.loader);
  25. document.observe('click', this.dispatchClick.bindAsEventListener(this));
  26. // Flash workaround for Gecko on Windows
  27. if(Prototype.Browser.Gecko && navigator.userAgent.indexOf('Windows') > 0) {
  28. document.observe('dialogbox:open', function(){
  29. $$('.swf').each(function(el){
  30. var flashObject = el.down('object');
  31. var wmode = flashObject.getAttribute('wmode');
  32. if(!wmode || wmode != 'transparent') {
  33. flashObject.setAttribute('wmode', 'transparent');
  34. flashObject.parentNode.replaceChild(flashObject.cloneNode(true), flashObject);
  35. }
  36. });
  37. });
  38. document.observe('dialogbox:close', function(){
  39. $$('.swf').each(function(el){
  40. var flashObject = el.down('object');
  41. var wmode = flashObject.getAttribute('wmode');
  42. // Restore previous wmode setting or remove the attribute
  43. if(wmode && wmode == 'transparent') {
  44. flashObject.removeAttribute('wmode');
  45. }
  46. flashObject.parentNode.replaceChild(flashObject.cloneNode(true), flashObject);
  47. });
  48. });
  49. }
  50. // Fix for Webkit inability to animate visibility property.
  51. if(typeof WebKitTransitionEvent !== 'undefined') {
  52. document.addEventListener('webkitTransitionEnd', function(e){
  53. var el = $(e.target);
  54. if(e.propertyName === 'visibility' && el.hasClassName('dialogbox_dialog') && !el.hasClassName('active'))
  55. el.setStyle({'visibility': 'hidden'});
  56. }, false);
  57. }
  58. this.initialized = true;
  59. },
  60. /**
  61. * DialogBox#resetWebkitTransitions()
  62. *
  63. * Really dirty method to resolve a Webkit bug with CSS transitions when some transitions does not start after another ones.
  64. * This method and it calls should be removed as Webkit bug disappears.
  65. *
  66. **/
  67. resetWebkitTransitions: function(){
  68. var dummy = document.createElement('DIV');
  69. dummy.style.position = 'fixed';
  70. dummy.style.width = '1px';
  71. dummy.style.height = '1px';
  72. dummy.style.zIndex = 1;
  73. dummy.style.webkitTransitionProperty = '-webkit-transform';
  74. dummy.style.webkitTransitionDuration = '.1s';
  75. dummy.style.webkitTransform = 'scale(1)';
  76. Element.insert(document.body, dummy);
  77. (function(){
  78. dummy.style.webkitTransform = 'scale(0)';
  79. }).delay(.1);
  80. (function(){
  81. Element.remove(dummy);
  82. }).delay(.2);
  83. },
  84. dispatchClick: function(event) {
  85. if (!event) return;
  86. var el = event.findElement('*[rel]');
  87. if(Object.isUndefined(el)) el = event.findElement('a[class*="image-zoom-actuator"]'); // Backward compatibility to work with classnames too. Deprecated.
  88. if(Object.isUndefined(el)) return;
  89. // CSS transitions are really buggy in Webkit and Safari. So we'll try to overcome it.
  90. if(typeof WebKitTransitionEvent !== 'undefined') this.resetWebkitTransitions();
  91. var rel = el.getAttribute('rel');
  92. if(rel) {
  93. rel = rel.split('[');
  94. var action = rel[0];
  95. var options = rel.length > 1 ? this.parseParams(rel[1].gsub(/]/,'')) : null;
  96. switch(action) {
  97. case 'dialogbox:open':
  98. event.preventDefault();
  99. this.show(el, options);
  100. break;
  101. case 'dialogbox:close':
  102. event.preventDefault();
  103. this.hide();
  104. break;
  105. }
  106. } else {
  107. // Backward compatibility to work with classnames too. Deprecated.
  108. if (el.hasClassName('image-zoom-actuator')) {
  109. event.preventDefault();
  110. this.show(el);
  111. }
  112. }
  113. },
  114. parseParams: function(params){
  115. try {
  116. var options = params.evalJSON(true);
  117. // Valid options hash is set as params. Eval and return it.
  118. if(options) return options;
  119. else return null;
  120. } catch(e) {
  121. var vals = params.split(',');
  122. // Width and height values are set as params. Build options hash and return it.
  123. if (vals.length == 2)
  124. return {
  125. 'width': vals[0],
  126. 'height': vals[1]
  127. };
  128. else return null;
  129. }
  130. },
  131. show: function(url, options) {
  132. Object.extend(this.options, this.default_options);
  133. Object.extend(this.options, options || {});
  134. $$('html')[0].addClassName('dialogbox');
  135. $$('body')[0].addClassName('dialogbox');
  136. this.overlay.addClassName('active');
  137. document.fire('dialogbox:open');
  138. // Preload content from url
  139. this.preload(
  140. url,
  141. function(content){
  142. this.display(content);
  143. }.bind(this),
  144. function(request){
  145. if(typeof console !== 'undefined'){console.error(request.statusText)};
  146. }
  147. );
  148. },
  149. preload: function(url, success, failure){
  150. this.loader.addClassName('active');
  151. var isImage = new RegExp(/\.jpg|\.png|\.gif\?\d*\Z/i);
  152. if(url.match(isImage)) {
  153. Asset.load(url, function(src){
  154. this.loader.removeClassName('active');
  155. var image = new Element('img', { 'src': src, 'rel': 'dialogbox:close' });
  156. this.options.width = image.width;
  157. this.options.height = image.height;
  158. if(Object.isFunction(success)) success(image);
  159. }.bind(this));
  160. } else {
  161. new Ajax.Request(url, {
  162. method: 'get',
  163. onComplete: function(){
  164. this.loader.removeClassName('active');
  165. }.bind(this),
  166. onSuccess: function(transport){
  167. if(Object.isFunction(success)) success(transport.responseText);
  168. },
  169. onFailure: function(transport){
  170. if(Object.isFunction(failure)) failure(transport);
  171. }
  172. });
  173. }
  174. },
  175. display: function(content){
  176. this.loader.removeClassName('active');
  177. this.content.update(content);
  178. this.box.setStyle({
  179. 'marginTop': - Math.round(this.options.height / 2) + 'px',
  180. 'marginLeft': - Math.round(this.options.width / 2) + 'px',
  181. 'width': this.options.width + 'px',
  182. 'height': this.options.height + 'px',
  183. 'visibility': 'visible'
  184. }).addClassName('active');
  185. },
  186. hide: function() {
  187. this.loader.removeClassName('active');
  188. this.overlay.removeClassName('active');
  189. this.box.removeClassName('active');
  190. if(typeof WebKitTransitionEvent !== 'undefined') this.box.setStyle({'visibility': 'visible'}); // Fix for Webkit inability to animate visibility property.
  191. else this.box.setStyle({'visibility': 'hidden'});
  192. $$('html')[0].removeClassName('dialogbox');
  193. $$('body')[0].removeClassName('dialogbox');
  194. document.fire('dialogbox:close');
  195. }
  196. };
  197. document.on('dom:loaded', function(){
  198. DialogBox.initialize();
  199. });
  200. /**
  201. * class Asset
  202. *
  203. * Implements images queue loading on request.
  204. * Calls callback with loaded image element when loading is completed.
  205. *
  206. **/
  207. var Asset = {
  208. assets: [],
  209. load: function(url, load) {
  210. var image = new Image();
  211. image.src = url;
  212. this.assets.push({ image: image, onLoad: load || Prototype.emptyFunction });
  213. this.wait();
  214. },
  215. wait: function() {
  216. if (this.interval) return;
  217. this.interval = setInterval(this.check.bind(this), 10);
  218. },
  219. check: function() {
  220. // Filter queue. If loading is completed, call the callback (if defined) and remove asset from queue.
  221. this.assets = this.assets.map(function(asset) {
  222. if (asset.image.complete) {
  223. if (typeof asset.onLoad === 'function') asset.onLoad(asset.image.src);
  224. return null;
  225. } else {
  226. return asset;
  227. }
  228. }).compact();
  229. // No assets left in the queue
  230. if (this.assets.length == 0) {
  231. clearInterval(this.interval);
  232. this.interval = null;
  233. }
  234. }
  235. };