Joomla! PHP Cross Reference Web Portals

Source: /media/system/js/modal-uncompressed.js - 460 lines - 13137 bytes - Text - Print

Description: SqueezeBox - Expandable Lightbox

   1  /**
   2   * SqueezeBox - Expandable Lightbox
   3   *
   4   * Allows to open various content as modal,
   5   * centered and animated box.
   6   *
   7   * Dependencies: MooTools 1.4 or newer
   8   *
   9   * Inspired by
  10   *  ... Lokesh Dhakar    - The original Lightbox v2
  11   *
  12   * @version        1.3
  13   *
  14   * @license        MIT-style license
  15   * @author        Harald Kirschner <mail [at] digitarald.de>
  16   * @author        Rouven Weßling <me [at] rouvenwessling.de>
  17   * @copyright    Author
  18   */
  19  
  20  var SqueezeBox = {
  21  
  22      presets: {
  23          onOpen: function(){},
  24          onClose: function(){},
  25          onUpdate: function(){},
  26          onResize: function(){},
  27          onMove: function(){},
  28          onShow: function(){},
  29          onHide: function(){},
  30          size: {x: 600, y: 450},
  31          sizeLoading: {x: 200, y: 150},
  32          marginInner: {x: 20, y: 20},
  33          marginImage: {x: 50, y: 75},
  34          handler: false,
  35          target: null,
  36          closable: true,
  37          closeBtn: true,
  38          zIndex: 65555,
  39          overlayOpacity: 0.7,
  40          classWindow: '',
  41          classOverlay: '',
  42          overlayFx: {},
  43          resizeFx: {},
  44          contentFx: {},
  45          parse: false, // 'rel'
  46          parseSecure: false,
  47          shadow: true,
  48          overlay: true,
  49          document: null,
  50          ajaxOptions: {}
  51      },
  52  
  53      initialize: function(presets) {
  54          if (this.options) return this;
  55  
  56          this.presets = Object.merge(this.presets, presets);
  57          this.doc = this.presets.document || document;
  58          this.options = {};
  59          this.setOptions(this.presets).build();
  60          this.bound = {
  61              window: this.reposition.bind(this, [null]),
  62              scroll: this.checkTarget.bind(this),
  63              close: this.close.bind(this),
  64              key: this.onKey.bind(this)
  65          };
  66          this.isOpen = this.isLoading = false;
  67          return this;
  68      },
  69  
  70      build: function() {
  71          this.overlay = new Element('div', {
  72              id: 'sbox-overlay',
  73              'aria-hidden': 'true',
  74              styles: { zIndex: this.options.zIndex},
  75              tabindex: -1
  76          });
  77          this.win = new Element('div', {
  78              id: 'sbox-window',
  79              role: 'dialog',
  80              'aria-hidden': 'true',
  81              styles: {zIndex: this.options.zIndex + 2}
  82          });
  83          if (this.options.shadow) {
  84              if (Browser.chrome
  85              || (Browser.safari && Browser.version >= 3)
  86              || (Browser.opera && Browser.version >= 10.5)
  87              || (Browser.firefox && Browser.version >= 3.5)
  88              || (Browser.ie && Browser.version >= 9)) {
  89                  this.win.addClass('shadow');
  90              } else if (!Browser.ie6) {
  91                  var shadow = new Element('div', {'class': 'sbox-bg-wrap'}).inject(this.win);
  92                  var relay = function(e) {
  93                      this.overlay.fireEvent('click', [e]);
  94                  }.bind(this);
  95                  ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'].each(function(dir) {
  96                      new Element('div', {'class': 'sbox-bg sbox-bg-' + dir}).inject(shadow).addEvent('click', relay);
  97                  });
  98              }
  99          }
 100          this.content = new Element('div', {id: 'sbox-content'}).inject(this.win);
 101          this.closeBtn = new Element('a', {id: 'sbox-btn-close', href: '#', role: 'button'}).inject(this.win);
 102          this.closeBtn.setProperty('aria-controls', 'sbox-window');
 103          this.fx = {
 104              overlay: new Fx.Tween(this.overlay, Object.merge({
 105                  property: 'opacity',
 106                  onStart: Events.prototype.clearChain,
 107                  duration: 250,
 108                  link: 'cancel'
 109              }, this.options.overlayFx)).set(0),
 110              win: new Fx.Morph(this.win, Object.merge({
 111                  onStart: Events.prototype.clearChain,
 112                  unit: 'px',
 113                  duration: 750,
 114                  transition: Fx.Transitions.Quint.easeOut,
 115                  link: 'cancel',
 116                  unit: 'px'
 117              }, this.options.resizeFx)),
 118              content: new Fx.Tween(this.content, Object.merge({
 119                  property: 'opacity',
 120                  duration: 250,
 121                  link: 'cancel'
 122              }, this.options.contentFx)).set(0)
 123          };
 124          document.id(this.doc.body).adopt(this.overlay, this.win);
 125      },
 126  
 127      assign: function(to, options) {
 128          return (document.id(to) || $$(to)).addEvent('click', function() {
 129              return !SqueezeBox.fromElement(this, options);
 130          });
 131      },
 132      
 133      open: function(subject, options) {
 134          this.initialize();
 135  
 136          if (this.element != null) this.trash();
 137          this.element = document.id(subject) || false;
 138  
 139          this.setOptions(Object.merge(this.presets, options || {}));
 140  
 141          if (this.element && this.options.parse) {
 142              var obj = this.element.getProperty(this.options.parse);
 143              if (obj && (obj = JSON.decode(obj, this.options.parseSecure))) this.setOptions(obj);
 144          }
 145          this.url = ((this.element) ? (this.element.get('href')) : subject) || this.options.url || '';
 146  
 147          this.assignOptions();
 148  
 149          var handler = handler || this.options.handler;
 150          if (handler) return this.setContent(handler, this.parsers[handler].call(this, true));
 151          var ret = false;
 152          return this.parsers.some(function(parser, key) {
 153              var content = parser.call(this);
 154              if (content) {
 155                  ret = this.setContent(key, content);
 156                  return true;
 157              }
 158              return false;
 159          }, this);
 160      },
 161      
 162      fromElement: function(from, options) {
 163          return this.open(from, options);
 164      },
 165  
 166      assignOptions: function() {
 167          this.overlay.addClass(this.options.classOverlay);
 168          this.win.addClass(this.options.classWindow);
 169      },
 170  
 171      close: function(e) {
 172          var stoppable = (typeOf(e) == 'domevent');
 173          if (stoppable) e.stop();
 174          if (!this.isOpen || (stoppable && !Function.from(this.options.closable).call(this, e))) return this;
 175          this.fx.overlay.start(0).chain(this.toggleOverlay.bind(this));
 176          this.win.setProperty('aria-hidden', 'true');
 177          this.fireEvent('onClose', [this.content]);
 178          this.trash();
 179          this.toggleListeners();
 180          this.isOpen = false;
 181          return this;
 182      },
 183  
 184      trash: function() {
 185          this.element = this.asset = null;
 186          this.content.empty();
 187          this.options = {};
 188          this.removeEvents().setOptions(this.presets).callChain();
 189      },
 190  
 191      onError: function() {
 192          this.asset = null;
 193          this.setContent('string', this.options.errorMsg || 'An error occurred');
 194      },
 195  
 196      setContent: function(handler, content) {
 197          if (!this.handlers[handler]) return false;
 198          this.content.className = 'sbox-content-' + handler;
 199          this.applyTimer = this.applyContent.delay(this.fx.overlay.options.duration, this, this.handlers[handler].call(this, content));
 200          if (this.overlay.retrieve('opacity')) return this;
 201          this.toggleOverlay(true);
 202          this.fx.overlay.start(this.options.overlayOpacity);
 203          return this.reposition();
 204      },
 205  
 206      applyContent: function(content, size) {
 207          if (!this.isOpen && !this.applyTimer) return;
 208          this.applyTimer = clearTimeout(this.applyTimer);
 209          this.hideContent();
 210          if (!content) {
 211              this.toggleLoading(true);
 212          } else {
 213              if (this.isLoading) this.toggleLoading(false);
 214              this.fireEvent('onUpdate', [this.content], 20);
 215          }
 216          if (content) {
 217              if (['string', 'array'].contains(typeOf(content))) {
 218                  this.content.set('html', content);
 219              } else if (!(content !== this.content && this.content.contains(content))) {
 220                  this.content.adopt(content);
 221              }
 222          }
 223          this.callChain();
 224          if (!this.isOpen) {
 225              this.toggleListeners(true);
 226              this.resize(size, true);
 227              this.isOpen = true;
 228              this.win.setProperty('aria-hidden', 'false');
 229              this.fireEvent('onOpen', [this.content]);
 230          } else {
 231              this.resize(size);
 232          }
 233      },
 234  
 235      resize: function(size, instantly) {
 236          this.showTimer = clearTimeout(this.showTimer || null);
 237          var box = this.doc.getSize(), scroll = this.doc.getScroll();
 238          this.size = Object.merge((this.isLoading) ? this.options.sizeLoading : this.options.size, size);
 239          var parentSize = self.getSize();
 240          if (this.size.x == parentSize.x) {
 241              this.size.y = this.size.y - 50;
 242              this.size.x = this.size.x - 20;
 243          }
 244          var to = {
 245              width: this.size.x,
 246              height: this.size.y,
 247              left: (scroll.x + (box.x - this.size.x - this.options.marginInner.x) / 2).toInt(),
 248              top: (scroll.y + (box.y - this.size.y - this.options.marginInner.y) / 2).toInt()
 249          };
 250          this.hideContent();
 251          if (!instantly) {
 252              this.fx.win.start(to).chain(this.showContent.bind(this));
 253          } else {
 254              this.win.setStyles(to);
 255              this.showTimer = this.showContent.delay(50, this);
 256          }
 257          return this.reposition();
 258      },
 259  
 260      toggleListeners: function(state) {
 261          var fn = (state) ? 'addEvent' : 'removeEvent';
 262          this.closeBtn[fn]('click', this.bound.close);
 263          this.overlay[fn]('click', this.bound.close);
 264          this.doc[fn]('keydown', this.bound.key)[fn]('mousewheel', this.bound.scroll);
 265          this.doc.getWindow()[fn]('resize', this.bound.window)[fn]('scroll', this.bound.window);
 266      },
 267  
 268      toggleLoading: function(state) {
 269          this.isLoading = state;
 270          this.win[(state) ? 'addClass' : 'removeClass']('sbox-loading');
 271          if (state) {
 272              this.win.setProperty('aria-busy', state);
 273              this.fireEvent('onLoading', [this.win]);
 274          }
 275      },
 276  
 277      toggleOverlay: function(state) {
 278          if (this.options.overlay) {
 279              var full = this.doc.getSize().x;
 280              this.overlay.set('aria-hidden', (state) ? 'false' : 'true');
 281              this.doc.body[(state) ? 'addClass' : 'removeClass']('body-overlayed');
 282              if (state) {
 283                  this.scrollOffset = this.doc.getWindow().getSize().x - full;
 284              } else {
 285                  this.doc.body.setStyle('margin-right', '');
 286              }
 287          }
 288      },
 289  
 290      showContent: function() {
 291          if (this.content.get('opacity')) this.fireEvent('onShow', [this.win]);
 292          this.fx.content.start(1);
 293      },
 294  
 295      hideContent: function() {
 296          if (!this.content.get('opacity')) this.fireEvent('onHide', [this.win]);
 297          this.fx.content.cancel().set(0);
 298      },
 299  
 300      onKey: function(e) {
 301          switch (e.key) {
 302              case 'esc': this.close(e);
 303              case 'up': case 'down': return false;
 304          }
 305      },
 306  
 307      checkTarget: function(e) {
 308          return e.target !== this.content && this.content.contains(e.target);
 309      },
 310  
 311      reposition: function() {
 312          var size = this.doc.getSize(), scroll = this.doc.getScroll(), ssize = this.doc.getScrollSize();
 313          var over = this.overlay.getStyles('height');
 314          var j = parseInt(over.height);
 315          if (ssize.y > j && size.y >= j) {
 316              this.overlay.setStyles({
 317                  width: ssize.x + 'px',
 318                  height: ssize.y + 'px'
 319              });
 320              this.win.setStyles({
 321                  left: (scroll.x + (size.x - this.win.offsetWidth) / 2 - this.scrollOffset).toInt() + 'px',
 322                  top: (scroll.y + (size.y - this.win.offsetHeight) / 2).toInt() + 'px'
 323              });
 324          }
 325          return this.fireEvent('onMove', [this.overlay, this.win]);
 326      },
 327  
 328      removeEvents: function(type){
 329          if (!this.$events) return this;
 330          if (!type) this.$events = null;
 331          else if (this.$events[type]) this.$events[type] = null;
 332          return this;
 333      },
 334  
 335      extend: function(properties) {
 336          return Object.append(this, properties);
 337      },
 338  
 339      handlers: new Hash(),
 340  
 341      parsers: new Hash()
 342  };
 343  
 344  SqueezeBox.extend(new Events(function(){})).extend(new Options(function(){})).extend(new Chain(function(){}));
 345  
 346  SqueezeBox.parsers.extend({
 347  
 348      image: function(preset) {
 349          return (preset || (/\.(?:jpg|png|gif)$/i).test(this.url)) ? this.url : false;
 350      },
 351  
 352      clone: function(preset) {
 353          if (document.id(this.options.target)) return document.id(this.options.target);
 354          if (this.element && !this.element.parentNode) return this.element;
 355          var bits = this.url.match(/#([\w-]+)$/);
 356          return (bits) ? document.id(bits[1]) : (preset ? this.element : false);
 357      },
 358  
 359      ajax: function(preset) {
 360          return (preset || (this.url && !(/^(?:javascript|#)/i).test(this.url))) ? this.url : false;
 361      },
 362  
 363      iframe: function(preset) {
 364          return (preset || this.url) ? this.url : false;
 365      },
 366  
 367      string: function(preset) {
 368          return true;
 369      }
 370  });
 371  
 372  SqueezeBox.handlers.extend({
 373  
 374      image: function(url) {
 375          var size, tmp = new Image();
 376          this.asset = null;
 377          tmp.onload = tmp.onabort = tmp.onerror = (function() {
 378              tmp.onload = tmp.onabort = tmp.onerror = null;
 379              if (!tmp.width) {
 380                  this.onError.delay(10, this);
 381                  return;
 382              }
 383              var box = this.doc.getSize();
 384              box.x -= this.options.marginImage.x;
 385              box.y -= this.options.marginImage.y;
 386              size = {x: tmp.width, y: tmp.height};
 387              for (var i = 2; i--;) {
 388                  if (size.x > box.x) {
 389                      size.y *= box.x / size.x;
 390                      size.x = box.x;
 391                  } else if (size.y > box.y) {
 392                      size.x *= box.y / size.y;
 393                      size.y = box.y;
 394                  }
 395              }
 396              size.x = size.x.toInt();
 397              size.y = size.y.toInt();
 398              this.asset = document.id(tmp);
 399              tmp = null;
 400              this.asset.width = size.x;
 401              this.asset.height = size.y;
 402              this.applyContent(this.asset, size);
 403          }).bind(this);
 404          tmp.src = url;
 405          if (tmp && tmp.onload && tmp.complete) tmp.onload();
 406          return (this.asset) ? [this.asset, size] : null;
 407      },
 408  
 409      clone: function(el) {
 410          if (el) return el.clone();
 411          return this.onError();
 412      },
 413  
 414      adopt: function(el) {
 415          if (el) return el;
 416          return this.onError();
 417      },
 418  
 419      ajax: function(url) {
 420          var options = this.options.ajaxOptions || {};
 421          this.asset = new Request.HTML(Object.merge({
 422              method: 'get',
 423              evalScripts: false
 424          }, this.options.ajaxOptions)).addEvents({
 425              onSuccess: function(resp) {
 426                  this.applyContent(resp);
 427                  if (options.evalScripts !== null && !options.evalScripts) Browser.exec(this.asset.response.javascript);
 428                  this.fireEvent('onAjax', [resp, this.asset]);
 429                  this.asset = null;
 430              }.bind(this),
 431              onFailure: this.onError.bind(this)
 432          });
 433          this.asset.send.delay(10, this.asset, [{url: url}]);
 434      },
 435  
 436      iframe: function(url) {
 437          this.asset = new Element('iframe', Object.merge({
 438              src: url,
 439              frameBorder: 0,
 440              width: this.options.size.x,
 441              height: this.options.size.y
 442          }, this.options.iframeOptions));
 443          if (this.options.iframePreload) {
 444              this.asset.addEvent('load', function() {
 445                  this.applyContent(this.asset.setStyle('display', ''));
 446              }.bind(this));
 447              this.asset.setStyle('display', 'none').inject(this.content);
 448              return false;
 449          }
 450          return this.asset;
 451      },
 452  
 453      string: function(str) {
 454          return str;
 455      }
 456  });
 457  
 458  SqueezeBox.handlers.url = SqueezeBox.handlers.ajax;
 459  SqueezeBox.parsers.url = SqueezeBox.parsers.ajax;
 460  SqueezeBox.parsers.adopt = SqueezeBox.parsers.clone;

title

Description

title

Description

title

Description

title

title

Body