UNPKG

formstone

Version:

Library of modular front end components.

1,228 lines (988 loc) 34.8 kB
/* global define */ // TODO: external controls like carousel? // TODO: Add swipe next/previous when zoomed out? (function(factory) { if (typeof define === "function" && define.amd) { define([ "jquery", "./core", "./transition" ], factory); } else { factory(jQuery, Formstone); } }(function($, Formstone) { "use strict"; /** * @method private * @name setup * @description Setup plugin. */ function setup() { scroll(); $Window.on("scroll", scroll); $Body = Formstone.$body; } /** * @method private * @name resize * @description Handles window resize */ function resize() { Functions.iterate.call($Instances, resizeInstance); // Functions.iterate.call($LazyInstances, cacheScrollPosition); // Functions.iterate.call($LazyInstances, checkScrollPosition); } /** * @method private * @name scroll * @description Handles window scroll */ function scroll() { ScrollTop = $Window.scrollTop() + Formstone.windowHeight; if (ScrollTop < 0) { ScrollTop = 0; } // Functions.iterate.call($LazyInstances, checkScrollPosition); } /** * @method private * @name raf * @description Handles request animation frame */ function raf() { Functions.iterate.call($Instances, renderRAF); } /** * @method private * @name cacheInstances * @description Caches active instances */ function cacheInstances() { $Instances = $(Classes.base); // $LazyInstances = $(Classes.lazy); // Functions.iterate.call($LazyInstances, cacheScrollPosition); if ($Instances.length) { Functions.lockViewport(Namespace); } else { Functions.unlockViewport(Namespace); } } /** * @method private * @name construct * @description Builds instance. * @param data [object] "Instance data" */ function construct(data) { var $image, imageData, html = '', controlPrevClasses = [RawClasses.control, RawClasses.control_previous].join(" "), controlNextClasses = [RawClasses.control, RawClasses.control_next].join(" "), controlZoomInClasses = [RawClasses.control, RawClasses.control_zoom_in].join(" "), controlZoomOutClasses = [RawClasses.control, RawClasses.control_zoom_out].join(" "); data.thisClasses = [RawClasses.base, RawClasses.loading, data.customClass, data.theme]; data.images = []; data.source = false; data.gallery = false; data.tapTimer = null; data.action = false; data.isRendering = false; data.isZooming = false; data.isAnimating = false; data.keyDownTime = 1; data.$images = this.find("img").addClass(RawClasses.source); data.index = 0; data.total = data.$images.length - 1; // Check custom controls data.customControls = ($.type(data.controls) === "object" && data.controls.zoom_in && data.controls.zoom_out); if (data.$images.length > 1) { data.gallery = true; data.thisClasses.push(RawClasses.gallery); // Requie zoom for gallery custom controls if (data.customControls && (!data.controls.previous || !data.controls.next)) { data.customControls = false; } } for (var i = 0; i < data.$images.length; i++) { $image = data.$images.eq(i); data.images.push($image.attr("src")); } html += '<div class="' + RawClasses.wrapper + '">'; html += '<div class="' + RawClasses.loading_icon + '"></div>'; html += '<div class="' + RawClasses.viewport + '"></div>'; html += '</div>'; // wrapper if (data.controls && !data.customControls) { html += '<div class="' + RawClasses.controls + '">'; html += '<button type="button" class="' + controlPrevClasses + '">' + data.labels.previous + '</button>'; html += '<button type="button" class="' + controlZoomOutClasses + '">' + data.labels.zoom_out + '</button>'; html += '<button type="button" class="' + controlZoomInClasses + '">' + data.labels.zoom_in + '</button>'; html += '<button type="button" class="' + controlNextClasses + '">' + data.labels.next + '</button>'; html += '</div>'; // controls } this.addClass(data.thisClasses.join(" ")) .prepend(html); data.$wrapper = this.find(Classes.wrapper); data.$viewport = this.find(Classes.viewport); if (data.customControls) { data.$controls = $(data.controls.container).addClass([RawClasses.controls, RawClasses.controls_custom].join(" ")); data.$controlPrevious = $(data.controls.previous).addClass(controlPrevClasses); data.$controlNext = $(data.controls.next).addClass(controlNextClasses); data.$controlZoomIn = $(data.controls.zoom_in).addClass(controlZoomInClasses); data.$controlZoomOut = $(data.controls.zoom_out).addClass(controlZoomOutClasses); } else { data.$controls = this.find(Classes.controls); data.$controlPrevious = this.find(Classes.control_previous); data.$controlNext = this.find(Classes.control_next); data.$controlZoomIn = this.find(Classes.control_zoom_in); data.$controlZoomOut = this.find(Classes.control_zoom_out); } data.$controlItems = data.$controlPrevious.add(data.$controlNext); data.$controlZooms = data.$controlZoomIn.add(data.$controlZoomOut); cacheInstances(); data.$controlItems.on(Events.click, data, advanceGallery); data.$controlZooms.on([Events.touchStart, Events.mouseDown].join(" "), data, onZoomStart) .on([Events.touchEnd, Events.mouseUp].join(" "), data, onClearZoom); // if (data.lazy) { // checkScrollPosition(data); // } else { loadImage(data, data.images[data.index], true); // } updateControls(data); } /** * @method private * @name destruct * @description Tears down instance. * @param data [object] "Instance data" */ function destruct(data) { data.$wrapper.remove(); data.$image.removeClass(RawClasses.source); if (data.controls && !data.customControls) { data.$controls.remove(); } if (data.customControls) { data.$controls.removeClass([RawClasses.controls, RawClasses.controls_custom].join(" ")); data.$controlItems.off(Events.click).removeClass([RawClasses.control, RawClasses.control_previous, RawClasses.control_next].join(" ")); data.$controlZooms.off([Events.touchStart, Events.mouseDown].join(" ")) .off([Events.touchStart, Events.mouseDown].join(" ")) .off([Events.touchEnd, Events.mouseUp].join(" ")) .removeClass([RawClasses.control, RawClasses.control_zoom_in, RawClasses.control_zoom_out].join(" ")); } this.removeClass(data.thisClasses.join(" ")) .off(Events.namespace); cacheInstances(); } /** * @method * @name load * @description Loads source image * @param source [string OR array] "Source image (string) or array of images (array)" * @example $(".target").viewer("load", "path/to/image.jpg"); * @example $(".target").viewer("load", ["path/to/image-1.jpg","path/to/image-2.jpg"]); */ function load(data, source) { data.index = 0; if (typeof source === "string") { data.total = 0; data.images = [source]; data.gallery = false; data.$el.removeClass(RawClasses.gallery); } else { data.total = source.length - 1; data.images = source; if (source.length > 1) { data.gallery = true; data.$el.addClass(RawClasses.gallery); } source = data.images[data.index]; } unloadImage(data, function() { loadImage(data, source); }); } /** * @method private * @name loadInitialImage * @description Loads first source image * @param data [object] "Instance data" */ function loadInitialImage(data) { loadImage(data, data.images[data.index]); } /** * @method private * @name loadImage * @description Loads source image * @param data [object] "Instance data" * @param source [string] "Source image" * @param initialLoad [boolean] "Is initial load" */ function loadImage(data, source, initialLoad) { if (!data.isAnimating) { data.isAnimating = true; data.$container = $('<div class="' + RawClasses.container + '"><img></div>'); data.$image = data.$container.find("img"); data.$viewport.append(data.$container); // Load image data.$image.one(Events.load, function() { onImageReady(data); data.isAnimating = false; // Transition in data.$container.fsTransition({ property: "opacity" }, function() { // Loaded }); data.$el.removeClass(RawClasses.loading); data.$container.fsTouch({ pan: true, scale: true }).on(Events.scaleStart, data, onScaleStart) .on(Events.scaleEnd, data, onScaleEnd) .on(Events.scale, data, onScale); data.$el.trigger(Events.loaded); }).one(Events.error, data, loadError) .attr("src", source) .addClass(RawClasses.image); // Check if image is cached if (data.$image[0].complete || data.$image[0].readyState === 4) { data.$image.trigger(Events.load); } data.source = source; } } /** * @method private * @name loadError * @description Error when resource fails to load. */ function loadError(e) { var data = e.data; data.$el.trigger(Events.error); } /** * @method private * @name onImageReady * @description Sets up image data * @param data [object] "Instance data" */ // on initial load function onImageReady(data) { // Cache image properties // First for container cacheImageProps(data); // Cache viewport properties cacheViewportProps(data); // Set initial container position data.containerTop = (data.viewportHeight / 2); data.containerLeft = (data.viewportWidth / 2); // Cache image min max cacheImageMinMax(data); // Set initial image size data.imageHeight = data.naturalHeight; data.imageWidth = data.naturalWidth; // Size the image to fit into the viewport fitToViewport(data); // Cache container min max cacheContainerMinMax(data); // Cache image top left cacheImageTopLeft(data); // Cache last props cacheLastProps(data); // Cache render props cacheRenderProps(data); // Update dom var props = { containerTop: data.containerTop, containerLeft: data.containerLeft, imageHeight: data.imageHeight, imageWidth: data.imageWidth, imageTop: data.imageTop, imageLeft: data.imageLeft, }; setSizeAndPosition(data, props); data.isRendering = true; } /** * @method private * @name cacheImageProps * @description Caches image properties * @param data [object] "Instance data" */ function cacheImageProps(data) { var naturalSize = calculateNaturalSize(data.$image); data.naturalHeight = naturalSize.naturalHeight; data.naturalWidth = naturalSize.naturalWidth; data.ratioHorizontal = data.naturalHeight / data.naturalWidth; data.ratioVertical = data.naturalWidth / data.naturalHeight; data.isWide = (data.naturalWidth > data.naturalHeight); } /** * @method private * @name cacheViewportProps * @description Caches viewport properties * @param data [object] "Instance data" */ function cacheViewportProps(data) { data.viewportHeight = data.$viewport.outerHeight(); data.viewportWidth = data.$viewport.outerWidth(); } /** * @method private * @name cacheContainerProps * @description Caches container properties * @param data [object] "Instance data" */ function cacheContainerMinMax(data) { if (data.imageHeight <= data.viewportHeight) { data.containerMinTop = (data.viewportHeight / 2); data.containerMaxTop = (data.viewportHeight / 2); } else { data.containerMinTop = data.viewportHeight - (data.imageHeight / 2); data.containerMaxTop = (data.imageHeight / 2); } if (data.imageWidth <= data.viewportWidth) { data.containerMinLeft = (data.viewportWidth / 2); data.containerMaxLeft = (data.viewportWidth / 2); } else { data.containerMinLeft = data.viewportWidth - (data.imageWidth / 2); data.containerMaxLeft = (data.imageWidth / 2); } } /** * @method private * @name cacheImageMinMax * @description Caches image min and max based on viewport and size * @param data [object] "Instance data" */ function cacheImageMinMax(data) { // Set min if (data.isWide) { //WIDE data.imageMinWidth = data.viewportWidth; data.imageMinHeight = data.imageMinWidth * data.ratioHorizontal; if (data.imageMinHeight > data.viewportHeight) { data.imageMinHeight = data.viewportHeight; data.imageMinWidth = data.imageMinHeight * data.ratioVertical; } } else { //TALL data.imageMinHeight = data.viewportHeight; data.imageMinWidth = data.imageMinHeight * data.ratioVertical; if (data.imageMinWidth > data.viewportWidth) { data.imageMinWidth = data.viewportWidth; data.imageMinHeight = data.imageMinWidth * data.ratioHorizontal; } } // Check natural max against new min if (data.imageMinWidth > data.naturalWidth || data.imageMinHeight > data.naturalHeight) { data.imageMinHeight = data.naturalHeight; data.imageMinWidth = data.naturalWidth; } // Set max data.imageMaxHeight = data.naturalHeight; data.imageMaxWidth = data.naturalWidth; } /** * @method private * @name cacheImageTopLeft * @description Caches image top and left based on viewport and size * @param data [object] "Instance data" */ function cacheImageTopLeft(data) { data.imageTop = -(data.imageHeight / 2); data.imageLeft = -(data.imageWidth / 2); } /** * @method private * @name cacheLastProps * @description Caches last container and image properties * @param data [object] "Instance data" */ function cacheLastProps(data) { data.lastContainerTop = data.containerTop; data.lastContainerLeft = data.containerLeft; data.lastImageHeight = data.imageHeight; data.lastImageWidth = data.imageWidth; data.lastImageTop = data.imageTop; data.lastImageLeft = data.imageLeft; } /** * @method private * @name cacheRenderProps * @description Caches container and image render properties * @param data [object] "Instance data" */ function cacheRenderProps(data) { data.renderContainerTop = data.lastContainerTop; data.renderContainerLeft = data.lastContainerLeft; data.renderImageTop = data.lastImageTop; data.renderImageLeft = data.lastImageLeft; data.renderImageHeight = data.lastImageHeight; data.renderImageWidth = data.lastImageWidth; } /** * @method private * @name fitToViewport * @description Fits image to viewport size * @param data [object] "Instance data" */ function fitToViewport(data) { data.imageHeight = data.imageMinHeight; data.imageWidth = data.imageMinWidth; } /** * @method private * @name checkImageMinMax * @description Checks image properties against min and max * @param data [object] "Instance data" */ // on scale function checkImageMinMax(data) { if (data.imageHeight < data.imageMinHeight) { data.imageHeight = data.imageMinHeight; } if (data.imageHeight > data.imageMaxHeight) { data.imageHeight = data.imageMaxHeight; } if (data.imageWidth < data.imageMinWidth) { data.imageWidth = data.imageMinWidth; } if (data.imageWidth > data.imageMaxWidth) { data.imageWidth = data.imageMaxWidth; } } /** * @method private * @name checkContainerTopLeft * @description Checks container properties against top and left * @param data [object] "Instance data" */ function checkContainerTopLeft(data) { if (data.containerTop < data.containerMinTop) { data.containerTop = data.containerMinTop; } if (data.containerTop > data.containerMaxTop) { data.containerTop = data.containerMaxTop; } if (data.containerLeft < data.containerMinLeft) { data.containerLeft = data.containerMinLeft; } if (data.containerLeft > data.containerMaxLeft) { data.containerLeft = data.containerMaxLeft; } } /** * @method private * @name checkDoubleTap * @description Checks is double tapping * @param data [object] "Instance data" */ function checkDoubleTap(data) { if (data.tapTimer === null) { data.tapTimer = Functions.startTimer(data.tapTimer, 500, function() { clearDoubleTap(data); }); } else { clearDoubleTap(data); onImageZoom(data); } } /** * @method private * @name clearDoubleTap * @description Clears double tap timer * @param data [object] "Instance data" */ function clearDoubleTap(data) { Functions.clearTimer(data.tapTimer); data.tapTimer = null; } /** * @method private * @name setSizeAndPosition * @description Updates image and container DOM * @param data [object] "Instance data" */ function setSizeAndPosition(data, props) { if (Formstone.transform) { var scaleX = props.imageWidth / data.naturalWidth, scaleY = props.imageHeight / data.naturalHeight; data.$container.css(Formstone.transform, "translate3d(" + props.containerLeft + "px, " + props.containerTop + "px, 0)"); data.$image.css(Formstone.transform, "translate3d(-50%, -50%, 0) scale(" + scaleX + "," + scaleY + ")"); } else { data.$container.css({ top: props.containerTop, left: props.containerLeft }); data.$image.css({ height: props.imageHeight, width: props.imageWidth, top: props.imageTop, left: props.imageLeft }); } } /** * @method private * @name onScaleStart * @description Handles scale start event * @param e [object] "Event data" */ function onScaleStart(e) { var data = e.data; // Check double tap checkDoubleTap(data); // Cache previous values cacheLastProps(data); } /** * @method private * @name onScale * @description Handles scale event * @param e [object] "Event data" */ function onScale(e) { var data = e.data; // Clear double tap clearDoubleTap(data); data.isRendering = false; data.isZooming = false; var zoomed = (data.imageHeight > data.imageMinHeight + 1); // Change container position data.containerTop = data.lastContainerTop + e.deltaY; data.containerLeft = data.lastContainerLeft + e.deltaX; /* var diffX = data.lastContainerLeft - data.containerLeft, diffY = data.lastContainerTop - data.containerTop; data.containerLeft -= diffX; data.containerTop -= diffY; */ // Change image size data.imageHeight = data.lastImageHeight * e.scale; data.imageWidth = data.lastImageWidth * e.scale; // Cache container min max cacheContainerMinMax(data); // Check container top left checkContainerTopLeft(data); // Check image min max checkImageMinMax(data); // Cache image top left cacheImageTopLeft(data); // Update dom var props = { containerTop: data.containerTop, containerLeft: data.containerLeft, imageHeight: data.imageHeight, imageWidth: data.imageWidth, imageTop: data.imageTop, imageLeft: data.imageLeft, }; setSizeAndPosition(data, props); } /** * @method private * @name onScaleEnd * @description Handles scale end event * @param e [object] "Event data" */ function onScaleEnd(e) { var data = e.data; if (!data.isZooming) { // Cache last properties cacheLastProps(data); // Cache rander properties cacheRenderProps(data); data.isRendering = true; } } /** * @method private * @name onImageZoom * @description Zooms image in or out depending on current size * @param data [object] "Instance data" */ function onImageZoom(data) { var zoomed = (data.imageHeight > data.imageMinHeight + 1); data.isZooming = true; // Cache last properties cacheLastProps(data); // Cache rander properties cacheRenderProps(data); if (zoomed) { // zoomed in (go to min) data.imageHeight = data.imageMinHeight; data.imageWidth = data.imageMinWidth; } else { // zoomed out (go to max) data.imageHeight = data.imageMaxHeight; data.imageWidth = data.imageMaxWidth; } // Cache container min max cacheContainerMinMax(data); // Check container top left checkContainerTopLeft(data); // Cache image top left cacheImageTopLeft(data); data.isRendering = true; } /** * @method private * @name onZoomStart * @description Handle zoom start * @param e [object] "Event data" */ function onZoomStart(e) { Functions.killEvent(e); var $target = $(e.currentTarget), data = e.data, direction = ($target.hasClass(RawClasses.control_zoom_out)) ? 'out' : 'in'; if (direction === 'out') { onZoomOut(data); } else { onZoomIn(data); } } /** * @method private * @name onZoomIn * @description Handle zoom in * @param data [object] "Instance data" */ function onZoomIn(data) { data.keyDownTime = 1; data.action = 'zoom_in'; } /** * @method private * @name onZoomOut * @description Handle zoom out * @param data [object] "Instance data" */ function onZoomOut(data) { data.keyDownTime = 1; data.action = 'zoom_out'; } /** * @method private * @name onClearZoom * @description Handle clear zoom * @param e [object] "Event data" */ function onClearZoom(e) { var data = e.data; data.action = false; } /** * @method private * @name renderRAF * @description Updates DOM based on animation values * @param data [object] "Instance data" */ function renderRAF(data) { if (data.isRendering) { if (data.action) { data.keyDownTime += data.zoomIncrement; var delta = ((data.action === "zoom_out") ? -1 : 1) * Math.round((data.imageWidth * data.keyDownTime) - data.imageWidth); if (delta > data.zoomDelta) { delta = data.zoomDelta; } if (data.isWide) { data.imageWidth += delta; data.imageHeight = Math.round(data.imageWidth / data.ratioVertical); } else { data.imageHeight += delta; data.imageWidth = Math.round(data.imageHeight / data.ratioHorizontal); } // Check image min max checkImageMinMax(data); // Cache image top left cacheImageTopLeft(data); // Cache container min max cacheContainerMinMax(data); // Check container top left checkContainerTopLeft(data); } data.renderContainerTop += Math.round((data.containerTop - data.renderContainerTop) * data.zoomEnertia); data.renderContainerLeft += Math.round((data.containerLeft - data.renderContainerLeft) * data.zoomEnertia); data.renderImageTop += Math.round((data.imageTop - data.renderImageTop) * data.zoomEnertia); data.renderImageLeft += Math.round((data.imageLeft - data.renderImageLeft) * data.zoomEnertia); data.renderImageHeight += Math.round((data.imageHeight - data.renderImageHeight) * data.zoomEnertia); data.renderImageWidth += Math.round((data.imageWidth - data.renderImageWidth) * data.zoomEnertia); // Update DOM var props = { containerTop: data.renderContainerTop, containerLeft: data.renderContainerLeft, imageHeight: data.renderImageHeight, imageWidth: data.renderImageWidth, imageTop: data.renderImageTop, imageLeft: data.renderImageLeft, }; setSizeAndPosition(data, props); } } /** * @method * @name unload * @description Unloads current image * @example $(".target").viewer("unload"); */ function unload(data) { unloadImage(data); } /** * @method private * @name unloadImage * @description Unloads current image * @param data [object] "Instance data" * @param callback [function] "Callback function" */ function unloadImage(data, callback) { if (!data.isAnimating) { clearDoubleTap(data); data.isAnimating = true; data.isRendering = false; data.isZooming = false; clearTouch(data); data.$container.fsTransition({ property: "opacity" }, function() { data.isAnimating = false; data.$container.remove(); if (typeof callback === "function") { callback.call(window, data); } }); data.$el.addClass(RawClasses.loading); } } /** * @method private * @name advanceGallery * @description Advances gallery * @param e [object] "Event data" */ function advanceGallery(e) { Functions.killEvent(e); var $target = $(e.currentTarget), data = e.data, index = data.index + (($target.hasClass(RawClasses.control_next)) ? 1 : -1); if (!data.isAnimating) { if (index < 0) { index = 0; } if (index > data.total) { index = data.total; } if (index !== data.index) { data.index = index; unloadImage(data, function() { loadImage(data, data.images[data.index]); }); } updateControls(data); } } /** * @method private * @name updateControls * @description Update control states * @param data [object] Instance data */ function updateControls(data) { data.$controlItems.removeClass(RawClasses.control_disabled); if (data.index === 0) { data.$controlPrevious.addClass(RawClasses.control_disabled); } if (data.index === data.images.length - 1) { data.$controlNext.addClass(RawClasses.control_disabled); } } /** * @method private * @name resize * @description Resize target instance * @example $(".target").viewer("resize"); */ /** * @method private * @name resizeInstance * @description Handle window resize event * @param data [object] "Instance data" */ function resizeInstance(data) { cacheViewportProps(data); cacheContainerMinMax(data); cacheImageMinMax(data); cacheImageTopLeft(data); cacheContainerMinMax(data); checkContainerTopLeft(data); checkImageMinMax(data); } /** * @method private * @name clearTouch * @description Clears current touch action. */ function clearTouch(data) { if (data.$container && data.$container.length) { data.$container.fsTouch("destroy") .off(Events.scaleStart, onScaleStart) .off(Events.scaleEnd, onScaleEnd) .off(Events.scale, onScale); } } /** * @method private * @name cacheScrollPosition * @description Cahce target scroll position * @param data [object] "Instance data" */ function cacheScrollPosition(data) { data.scrollTop = data.$el.offset().top; } // /** // * @method private // * @name checkScrollPosition // * @description Check target scroll position against window // * @param data [object] "Instance data" // */ // // function checkScrollPosition(data) { // if (!data.visible && data.scrollTop < ScrollTop + data.lazyEdge) { // data.visible = true; // loadInitialImage(data); // } // } /** * @method private * @name calculateNaturalSize * @description Determines natural size of target image. * @param $img [jQuery object] "Source image object" * @return [object | boolean] "Object containing natural height and width values or false" */ function calculateNaturalSize($img) { var node = $img[0], img = new Image(); if (typeof node.naturalHeight !== "undefined") { return { naturalHeight: node.naturalHeight, naturalWidth: node.naturalWidth }; } else { if (node.tagName.toLowerCase() === 'img') { img.src = node.src; return { naturalHeight: img.height, naturalWidth: img.width }; } } return false; } /** * @plugin * @name Viewer * @description A jQuery plugin for image exploration. * @type widget * @main viewer.js * @main viewer.css * @dependency jQuery * @dependency core.js * @dependency touch.js * @dependency transition.js */ var Plugin = Formstone.Plugin("viewer", { widget: true, /** * @options * @param controls [boolean or object] <true> "Flag to draw controls OR object containing container, next, previous, zoom_in and zoom_out control selectors (Must be fully qualified selectors)" * @param customClass [string] <''> "Class applied to instance" // param lazy [boolean] <false> "Lazy load with scroll" // param lazyEdge [int] <100> "Lazy load edge" * @param labels.count [string] <'of'> "Gallery count separator text" * @param labels.next [string] <'Next'> "Gallery control text" * @param labels.previous [string] <'Previous'> "Gallery control text" * @param labels.zoom_in [string] <'Zoom In'> "Image zoom text" * @param labels.zoom_out [string] <'Zoom Out'> "Image zoom text" * @param theme [string] <"fs-light"> "Theme class name" * @param zoomDelta [int] <100> "Max zoom change" * @param zoomEnertia [float] <0.2> "Enertia for zoom" * @param zoomIncrement [float] <0.01> "Increment for zoom buttons" */ defaults: { controls: true, customClass: "", // lazy : false, // lazyEdge : 100, labels: { count: "of", next: "Next", previous: "Previous", zoom_in: "Zoom In", zoom_out: "Zoom Out" }, theme: "fs-light", zoomDelta: 100, zoomEnertia: 0.2, zoomIncrement: 0.01 }, classes: [ "source", "wrapper", "viewport", "container", "image", "gallery", "loading_icon", "controls", "controls_custom", "control", "control_previous", "control_next", "control_zoom_in", "control_zoom_out", "control_disabled", // "lazy" "loading" ], /** * @events * @event loaded.viewer "Image loaded" * @event ready.viewer "Image ready" */ events: { loaded: "loaded", ready: "ready" }, methods: { _construct: construct, _destruct: destruct, _resize: resize, _raf: raf, resize: resizeInstance, load: load, unload: unload } }), // Localize References Namespace = Plugin.namespace, Classes = Plugin.classes, RawClasses = Classes.raw, Events = Plugin.events, Functions = Plugin.functions, Window = Formstone.window, $Window = Formstone.$window, $Body, ScrollTop = 0, $Instances = [], ViewportSetup = false; // Setup Formstone.Ready(setup); }) );