IE9 = /MSIE 9./.test(navigator.userAgent)
class Backdrop
constructor: -> @isNestedBackdrop = $(".lighter-box-backdrop").length > 0 @backdrop = $("<div class='lighter-box-backdrop' />").appendTo("body") unless @isNestedBackdrop $("body").addClass("lighter-box-has-backdrop") $("body > *").wrapAll("<div class='lighter-box-aria-hide-body' aria-hidden='true' />") remove: => @backdrop.remove() unless @isNestedBackdrop $(".lighter-box-aria-hide-body > *").unwrap() $("body").removeClass("lighter-box-has-backdrop")
class Spinner
constructor: (@parentEl) -> @el = $("<div class='lighter-box-spinner' tabindex='0'><div class='lighter-box-sr-only'>wird geladen …</div><div class='rect1' /><div class='rect2' /><div class='rect3' /><div class='rect4' /><div class='rect5' /></div>").hide().appendTo(@parentEl) @delay = null showDelayed: (delayMS) => @_clearDelay() @delay = window.setTimeout(@show, delayMS) show: => @_clearDelay() @el.show().focus() remove: => @_clearDelay() @el.remove() @parentEl.focus() _clearDelay: => window.clearTimeout(@delay)
class LightboxGroup
constructor: (@currentEl) -> index: => @_elems().index(@currentEl) hasNext: => @index() + 1 < @_elems().length hasPrev: => @index() - 1 >= 0 nextHref: => @_elems().eq(@index() + 1).attr("href") prevHref: => @_elems().eq(@index() - 1).attr("href") next: => @currentEl = @_elems().eq(@index() + 1) prev: => @currentEl = @_elems().eq(@index() - 1) _elems: => if (groupName = @currentEl.attr("data-lightbox-group")) $("[data-lightbox-group='#{groupName}']:visible") else @currentEl
class ImageModalResizer
MIN_CAPTION_WIDTH: 200 constructor: (@modal) -> @figure = @modal.find("figure") @img = @figure.find("img") @figcaption = @figure.find("figcaption") @minImgHeight = parseInt(@img.css("min-height"), 10) @running = false run: => return if @running @running = true if window.requestAnimationFrame then window.requestAnimationFrame(@_run) else @_run() _run: => @img.css("max-height": "none") @modalHeight = @modal.height() @_resize() @_ie9Fix() if IE9 @running = false _resize: => if (overflow = @figure.height() - @modalHeight) > 0 if (newHeight = @img.height() - overflow) >= @minImgHeight @img.css("max-height": "#{newHeight}px") else @img.css("max-height": "#{@minImgHeight}px") return # Make sure we don't recurse any more captionWidth = Math.max(@img.width(), @MIN_CAPTION_WIDTH) @figcaption.css("max-width": captionWidth) @_resize() if @figure.height() > @modalHeight _ie9Fix: => left = (document.documentElement.clientWidth - @modal.outerWidth()) / 2 top = (document.documentElement.clientHeight - @modal.outerHeight()) / 2 @modal.css(left: "#{left}px", top: "#{top}px")
class LighterBox
constructor: (srcEl) -> @eventNamespace = "lighter-box-#{new Date().getTime()}" @srcEl = $(srcEl) @originalFocusEl = $(":focus") @lightboxGroup = new LightboxGroup(@srcEl) @backdrop = new Backdrop() @container = @_createContainer() @modal = @_createModal(@container) @modal.addClass(@srcEl.data("lightbox-class")).data("lighter-box", this) @_createInnerModal() @container.on("click.#{@eventNamespace}", (ev) => @hide() if ev.target == @container[0]) @container.on("click.#{@eventNamespace}", "[data-lighter-box-dismiss]", @hide) @container.on("click.#{@eventNamespace}", "[data-lighter-box-prev]", (ev) => ev.preventDefault(); @_showPrev()) @container.on("click.#{@eventNamespace}", "[data-lighter-box-next]", (ev) => ev.preventDefault(); @_showNext()) @container.on("keydown.#{@eventNamespace}", @_onKeydown) @_trapFocus() @modal.focus() @_setContent().then => @_ie9Fix() if IE9 hide: => @_releaseFocus() @container.off(".#{@eventNamespace}") $(window).off(".#{@eventNamespace}") @modal.trigger("lighter-box-will-hide", [this]) @container.remove() @backdrop.remove() @originalFocusEl.focus() _createContainer: () => $("<div class='lighter-box-container' />").appendTo("body") _createModal: (container) => modal = $("<div class='lighter-box-modal' role='dialog' aria-hidden='false' tabindex='0'/>").appendTo(container) $("<button class='lighter-box-close-button' title='Vergrößerte Ansicht schließen' data-lighter-box-dismiss><span aria-hidden='true'>×</span></button>").appendTo(container) $("<a data-lighter-box-prev class='lighter-box-prev-link' href='#' title='Voriges Bild'><span aria-hidden='true'>‹</span></a>").appendTo(container) $("<a data-lighter-box-next class='lighter-box-next-link' href='#' title='Nächstes Bild'><span aria-hidden='true'>›</span></a>").appendTo(container) modal _createInnerModal: => # Template method, override in subclasses if needed _setContent: => prevLink = @container.find("[data-lighter-box-prev]").hide() nextLink = @container.find("[data-lighter-box-next]").hide() spinner = new Spinner(@modal) spinner.showDelayed(100) @_loadContent().then => spinner.remove() prevLink.attr("href", @lightboxGroup.prevHref()).show() if @lightboxGroup.hasPrev() nextLink.attr("href", @lightboxGroup.nextHref()).show() if @lightboxGroup.hasNext() @modal.trigger("lighter-box-content-loaded", [this]) _loadContent: => throw "_loadContent needs to be overriden in a subclass." _trapFocus: => $(document).on "focusin.#{@eventNamespace}", (ev) => return unless @_isForemost() @modal.focus() unless $.contains(@container[0], ev.target) _releaseFocus: => $(document).off "focusin.#{@eventNamespace}" _onKeydown: (ev) => return unless @_isForemost() switch ev.which when 27 then ev.preventDefault(); @hide() when 39 then ev.preventDefault(); @_showNext() when 37 then ev.preventDefault(); @_showPrev() _showNext: => if @lightboxGroup.hasNext() @srcEl = @lightboxGroup.next() @_setContent() @modal.focus() _showPrev: => if @lightboxGroup.hasPrev() @srcEl = @lightboxGroup.prev() @_setContent() @modal.focus() _isForemost: => @container.nextAll(".lighter-box-container").length == 0 _ie9Fix: => @modal.addClass("ie9")
class ImageLighterBox extends LighterBox
constructor: (srcEl) -> super(srcEl) @resizer = new ImageModalResizer(@modal) $(window).on("resize.#{@eventNamespace}", => @resizer.run()) _createInnerModal: => figure = $("<figure />").appendTo(@modal) $("<figcaption id='lighter-box-figcaption' class='lighter-box-figcaption'/>").appendTo(figure) $("<img class='lighter-box-image'>").attr("aria-labelledby": "lighter-box-figcaption").prependTo(figure) _loadContent: => $.Deferred (deferred) => href = @srcEl.data("lightbox-href") || @srcEl.attr("href") caption = @srcEl.data("lightbox-caption") || @srcEl.find("img").attr("alt") || "" newImg = $("<img>").attr(src: href).one "load", => @modal.find("img").attr(src: newImg.attr("src")) @_setCaption(caption) @resizer.run() deferred.resolve() _ie9Fix: => super() @resizer.run() _setCaption: (caption) => figcaptionEl = @modal.find("figcaption") if @srcEl.data("lightbox-caption-allow-html") figcaptionEl.html(caption) else figcaptionEl.text(caption) figcaptionEl.toggleClass("empty-caption", caption.trim() == "")
class AjaxLighterBox extends LighterBox
constructor: (srcEl) -> super(srcEl) _createInnerModal: => @ajaxContainer = $("<div/>").appendTo(@modal) _loadContent: => href = @srcEl.data("lightbox-href") || @srcEl.attr("href") fragment = @srcEl.data("lightbox-fragment") $.get href, (data) => data = $("<div/>").append($.parseHTML(data)).find(fragment) @ajaxContainer.html(data)
window.LighterBox =
Ajax: AjaxLighterBox Image: ImageLighterBox