1/** 2 * SqueezeBox - Expandable Lightbox 3 * 4 * Allows to open various content as modal, 5 * centered and animated box. 6 * 7 * Inspired by 8 * ... Lokesh Dhakar - The original Lightbox v2 9 * ... Cody Lindley - ThickBox 10 * 11 * @version 1.0rc1 12 * 13 * @license MIT-style license 14 * @author Harald Kirschner <mail [at] digitarald.de> 15 * @copyright Author 16 */ 17var SqueezeBox = { 18 19 presets: { 20 size: {x: 600, y: 450}, 21 sizeLoading: {x: 200, y: 150}, 22 marginInner: {x: 20, y: 20}, 23 marginImage: {x: 150, y: 200}, 24 handler: false, 25 adopt: null, 26 closeWithOverlay: true, 27 zIndex: 65555, 28 overlayOpacity: 0.7, 29 classWindow: '', 30 classOverlay: '', 31 disableFx: false, 32 onOpen: Class.empty, 33 onClose: Class.empty, 34 onUpdate: Class.empty, 35 onResize: Class.empty, 36 onMove: Class.empty, 37 onShow: Class.empty, 38 onHide: Class.empty, 39 fxOverlayDuration: 250, 40 fxResizeDuration: 750, 41 fxContentDuration: 250, 42 ajaxOptions: {} 43 }, 44 45 initialize: function(options) { 46 if (this.options) return this; 47 this.presets = $merge(this.presets, options) 48 this.setOptions(this.presets); 49 this.build(); 50 this.listeners = { 51 window: this.reposition.bind(this, [null]), 52 close: this.close.bind(this), 53 key: this.onkeypress.bind(this)}; 54 this.isOpen = this.isLoading = false; 55 this.window.close = this.listeners.close; 56 return this; 57 }, 58 59 build: function() { 60 this.overlay = new Element('div', { 61 id: 'sbox-overlay', 62 styles: { 63 display: 'none', 64 zIndex: this.options.zIndex 65 } 66 }); 67 this.content = new Element('div', { 68 id: 'sbox-content' 69 }); 70 this.btnClose = new Element('a', { 71 id: 'sbox-btn-close', 72 href: '#' 73 }); 74 this.window = new Element('div', { 75 id: 'sbox-window', 76 styles: { 77 display: 'none', 78 zIndex: this.options.zIndex + 2 79 } 80 }).adopt(this.btnClose, this.content); 81 82 if (!window.ie6) { 83 this.overlay.setStyles({ 84 position: 'fixed', 85 top: 0, 86 left: 0 87 }); 88 this.window.setStyles({ 89 position: 'fixed', 90 top: '50%', 91 left: '50%' 92 }); 93 } else { 94 this.overlay.style.setExpression('marginTop', 'document.documentElement.scrollTop + "px"'); 95 this.window.style.setExpression('marginTop', '0 - parseInt(this.offsetHeight / 2) + document.documentElement.scrollTop + "px"'); 96 97 this.overlay.setStyles({ 98 position: 'absolute', 99 top: '0%', 100 left: '0%' 101 //,marginTop: "expression(document.documentElement.scrollTop + 'px')" 102 }); 103 104 this.window.setStyles({ 105 position: 'absolute', 106 top: '0%', 107 left: '0%' 108 //,marginTop: "(expression(0 - parseInt(this.offsetHeight / 2) + document.documentElement.scrollTop + 'px')" 109 }); 110 } 111 112 $(document.body).adopt(this.overlay, this.window); 113 114 this.fx = { 115 overlay: this.overlay.effect('opacity', { 116 duration: this.options.fxOverlayDuration, 117 wait: false}).set(0), 118 window: this.window.effects({ 119 duration: this.options.fxResizeDuration, 120 wait: false}), 121 content: this.content.effect('opacity', { 122 duration: this.options.fxContentDuration, 123 wait: false}).set(0) 124 }; 125 }, 126 127 addClick: function(el) { 128 return el.addEvent('click', function() { 129 if (this.fromElement(el)) return false; 130 }.bind(this)); 131 }, 132 133 fromElement: function(el, options) { 134 this.initialize(); 135 this.element = $(el); 136 if (this.element && this.element.rel) options = $merge(options || {}, Json.evaluate(this.element.rel)); 137 this.setOptions(this.presets, options); 138 this.assignOptions(); 139 this.url = (this.element ? (this.options.url || this.element.href) : el) || ''; 140 141 if (this.options.handler) { 142 var handler = this.options.handler; 143 return this.setContent(handler, this.parsers[handler].call(this, true)); 144 } 145 var res = false; 146 for (var key in this.parsers) { 147 if ((res = this.parsers[key].call(this))) return this.setContent(key, res); 148 } 149 return this; 150 }, 151 152 assignOptions: function() { 153 this.overlay.setProperty('class', this.options.classOverlay); 154 this.window.setProperty('class', this.options.classWindow); 155 }, 156 157 close: function(e) { 158 if (e) new Event(e).stop(); 159 if (!this.isOpen) return this; 160 this.fx.overlay.start(0).chain(this.toggleOverlay.bind(this)); 161 this.window.setStyle('display', 'none'); 162 this.trashImage(); 163 this.toggleListeners(); 164 this.isOpen = null; 165 this.fireEvent('onClose', [this.content]).removeEvents(); 166 this.options = {}; 167 this.setOptions(this.presets).callChain(); 168 return this; 169 }, 170 171 onError: function() { 172 if (this.image) this.trashImage(); 173 this.setContent('Error during loading'); 174 }, 175 176 trashImage: function() { 177 if (this.image) this.image = this.image.onload = this.image.onerror = this.image.onabort = null; 178 }, 179 180 setContent: function(handler, content) { 181 this.content.setProperty('class', 'sbox-content-' + handler); 182 this.applyTimer = this.applyContent.delay(this.fx.overlay.options.duration, this, [this.handlers[handler].call(this, content)]); 183 if (this.overlay.opacity) return this; 184 this.toggleOverlay(true); 185 this.fx.overlay.start(this.options.overlayOpacity); 186 this.reposition(); 187 return this; 188 }, 189 190 applyContent: function(content, size) { 191 this.applyTimer = $clear(this.applyTimer); 192 this.hideContent(); 193 if (!content) this.toggleLoading(true); 194 else { 195 if (this.isLoading) this.toggleLoading(false); 196 this.fireEvent('onUpdate', [this.content], 20); 197 } 198 this.content.empty()[['string', 'array', false].contains($type(content)) ? 'setHTML' : 'adopt'](content || ''); 199 this.callChain(); 200 if (!this.isOpen) { 201 this.toggleListeners(true); 202 this.resize(size, true); 203 this.isOpen = true; 204 this.fireEvent('onOpen', [this.content]); 205 } else this.resize(size); 206 }, 207 208 resize: function(size, instantly) { 209 var sizes = window.getSize(); 210 this.size = $merge(this.isLoading ? this.options.sizeLoading : this.options.size, size); 211 var to = { 212 width: this.size.x, 213 height: this.size.y, 214 marginLeft: - this.size.x / 2, 215 marginTop: - this.size.y / 2 216 //left: (sizes.scroll.x + (sizes.size.x - this.size.x - this.options.marginInner.x) / 2).toInt(), 217 //top: (sizes.scroll.y + (sizes.size.y - this.size.y - this.options.marginInner.y) / 2).toInt() 218 }; 219 $clear(this.showTimer || null); 220 this.hideContent(); 221 if (!instantly) this.fx.window.start(to).chain(this.showContent.bind(this)); 222 else { 223 this.window.setStyles(to).setStyle('display', ''); 224 this.showTimer = this.showContent.delay(50, this); 225 } 226 this.reposition(sizes); 227 }, 228 229 toggleListeners: function(state) { 230 var task = state ? 'addEvent' : 'removeEvent'; 231 this.btnClose[task]('click', this.listeners.close); 232 if (this.options.closeWithOverlay) this.overlay[task]('click', this.listeners.close);
233 document[task]('keydown', this.listeners.key); 234 window[task]('resize', this.listeners.window); 235 window[task]('scroll', this.listeners.window); 236 }, 237 238 toggleLoading: function(state) { 239 this.isLoading = state; 240 this.window[state ? 'addClass' : 'removeClass']('sbox-loading'); 241 if (state) this.fireEvent('onLoading', [this.window]); 242 }, 243 244 toggleOverlay: function(state) { 245 this.overlay.setStyle('display', state ? '' : 'none'); 246 $(document.body)[state ? 'addClass' : 'removeClass']('body-overlayed'); 247 }, 248 249 showContent: function() { 250 if (this.content.opacity) this.fireEvent('onShow', [this.window]); 251 this.fx.content.start(1); 252 }, 253 254 hideContent: function() { 255 if (!this.content.opacity) this.fireEvent('onHide', [this.window]); 256 this.fx.content.stop().set(0); 257 }, 258 259 onkeypress: function(e) { 260 switch (e.key) { 261 case 'esc': 262 case 'x': 263 this.close(); 264 break; 265 } 266 }, 267 268 reposition: function(sizes) { 269 sizes = sizes || window.getSize(); 270 this.overlay.setStyles({ 271 //'left': sizes.scroll.x, 'top': sizes.scroll.y, 272 width: sizes.size.x, 273 height: sizes.size.y 274 }); 275 /* 276 this.window.setStyles({ 277 left: (sizes.scroll.x + (sizes.size.x - this.window.offsetWidth) / 2).toInt(), 278 top: (sizes.scroll.y + (sizes.size.y - this.window.offsetHeight) / 2).toInt() 279 }); 280 */ 281 this.fireEvent('onMove', [this.overlay, this.window, sizes]); 282 }, 283 284 removeEvents: function(type){ 285 if (!this.$events) return this; 286 if (!type) this.$events = null; 287 else if (this.$events[type]) this.$events[type] = null; 288 return this; 289 }, 290 291 parsers: { 292 'image': function(preset) { 293 return (preset || this.url.test(/\.(jpg|jpeg|png|gif|bmp)$/i)) ? this.url : false; 294 }, 295 'adopt': function(preset) { 296 if ($(this.options.adopt)) return $(this.options.adopt); 297 if (preset || ($(this.element) && !this.element.parentNode)) return $(this.element); 298 var bits = this.url.match(/#([\w-]+)$/); 299 return bits ? $(bits[1]) : false; 300 }, 301 'url': function(preset) { 302 return (preset || (this.url && !this.url.test(/^javascript:/i))) ? this.url: false; 303 }, 304 'iframe': function(preset) { 305 return (preset || this.url) ? this.url: false; 306 }, 307 'string': function(preset) { 308 return true; 309 } 310 }, 311 312 handlers: { 313 'image': function(url) { 314 this.image = new Image(); 315 var events = { 316 loaded: function() { 317 var win = {x: window.getWidth() - this.options.marginImage.x, y: window.getHeight() - this.options.marginImage.y}; 318 var size = {x: this.image.width, y: this.image.height}; 319 for (var i = 0; i < 2; i++) 320 if (size.x > win.x) { 321 size.y *= win.x / size.x; 322 size.x = win.x; 323 } else if (size.y > win.y) { 324 size.x *= win.y / size.y; 325 size.y = win.y; 326 } 327 size = {x: parseInt(size.x), y: parseInt(size.y)}; 328 if (window.webkit419) this.image = new Element('img', {'src': this.image.src}); 329 else $(this.image); 330 this.image.setProperties({ 331 'width': size.x, 332 'height': size.y}); 333 this.applyContent(this.image, size); 334 }.bind(this), 335 failed: this.onError.bind(this) 336 }; 337 (function() { 338 this.src = url; 339 }).delay(10, this.image); 340 this.image.onload = events.loaded; 341 this.image.onerror = this.image.onabort = events.failed; 342 }, 343 'adopt': function(el) { 344 return el.clone(); 345 }, 346 'url': function(url) { 347 this.ajax = new Ajax(url, this.options.ajaxOptions); 348 this.ajax.addEvent('onSuccess', function(resp) { 349 this.applyContent(resp); 350 this.ajax = null; 351 }.bind(this)); 352 this.ajax.addEvent('onFailure', this.onError.bind(this)); 353 this.ajax.request.delay(10, this.ajax); 354 }, 355 'iframe': function(url) { 356 return new Element('iframe', { 357 'src': url, 358 'frameBorder': 0, 359 'width': this.options.size.x, 360 'height': this.options.size.y 361 }); 362 }, 363 'string': function(str) { 364 return str; 365 } 366 }, 367 368 extend: $extend 369}; 370 371SqueezeBox.extend(SqueezeBox, Events.prototype); 372SqueezeBox.extend(SqueezeBox, Options.prototype); 373SqueezeBox.extend(SqueezeBox, Chain.prototype);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.