From 3e8b34be2fdeccf16c8b46f1ee518f970853768d Mon Sep 17 00:00:00 2001 From: Mitch Riedstra Date: Tue, 24 Oct 2017 16:59:48 -0400 Subject: Adding in materialize source and templates --- app/dispatch/static/materialize/js/carousel.js | 565 +++++++++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 app/dispatch/static/materialize/js/carousel.js (limited to 'app/dispatch/static/materialize/js/carousel.js') diff --git a/app/dispatch/static/materialize/js/carousel.js b/app/dispatch/static/materialize/js/carousel.js new file mode 100644 index 0000000..44bb118 --- /dev/null +++ b/app/dispatch/static/materialize/js/carousel.js @@ -0,0 +1,565 @@ +(function ($) { + + var methods = { + + init : function(options) { + var defaults = { + duration: 200, // ms + dist: -100, // zoom scale TODO: make this more intuitive as an option + shift: 0, // spacing for center image + padding: 0, // Padding between non center items + fullWidth: false, // Change to full width styles + indicators: false, // Toggle indicators + noWrap: false, // Don't wrap around and cycle through items. + onCycleTo: null // Callback for when a new slide is cycled to. + }; + options = $.extend(defaults, options); + var namespace = Materialize.objectSelectorString($(this)); + + return this.each(function(i) { + + var images, item_width, item_height, offset, center, pressed, dim, count, + reference, referenceY, amplitude, target, velocity, scrolling, + xform, frame, timestamp, ticker, dragged, vertical_dragged; + var $indicators = $(''); + var scrollingTimeout = null; + var oneTimeCallback = null; + + + // Initialize + var view = $(this); + var hasMultipleSlides = view.find('.carousel-item').length > 1; + var showIndicators = (view.attr('data-indicators') || options.indicators) && hasMultipleSlides; + var noWrap = (view.attr('data-no-wrap') || options.noWrap) || !hasMultipleSlides; + var uniqueNamespace = view.attr('data-namespace') || namespace+i; + view.attr('data-namespace', uniqueNamespace); + + + // Options + var setCarouselHeight = function(imageOnly) { + var firstSlide = view.find('.carousel-item.active').length ? view.find('.carousel-item.active').first() : view.find('.carousel-item').first(); + var firstImage = firstSlide.find('img').first(); + if (firstImage.length) { + if (firstImage[0].complete) { + // If image won't trigger the load event + var imageHeight = firstImage.height(); + if (imageHeight > 0) { + view.css('height', firstImage.height()); + } else { + // If image still has no height, use the natural dimensions to calculate + var naturalWidth = firstImage[0].naturalWidth; + var naturalHeight = firstImage[0].naturalHeight; + var adjustedHeight = (view.width() / naturalWidth) * naturalHeight; + view.css('height', adjustedHeight); + } + } else { + // Get height when image is loaded normally + firstImage.on('load', function(){ + view.css('height', $(this).height()); + }); + } + } else if (!imageOnly) { + var slideHeight = firstSlide.height(); + view.css('height', slideHeight); + } + }; + + if (options.fullWidth) { + options.dist = 0; + setCarouselHeight(); + + // Offset fixed items when indicators. + if (showIndicators) { + view.find('.carousel-fixed-item').addClass('with-indicators'); + } + } + + + // Don't double initialize. + if (view.hasClass('initialized')) { + // Recalculate variables + $(window).trigger('resize'); + + // Redraw carousel. + view.trigger('carouselNext', [0.000001]); + return true; + } + + + view.addClass('initialized'); + pressed = false; + offset = target = 0; + images = []; + item_width = view.find('.carousel-item').first().innerWidth(); + item_height = view.find('.carousel-item').first().innerHeight(); + dim = item_width * 2 + options.padding; + + view.find('.carousel-item').each(function (i) { + images.push($(this)[0]); + if (showIndicators) { + var $indicator = $('
  • '); + + // Add active to first by default. + if (i === 0) { + $indicator.addClass('active'); + } + + // Handle clicks on indicators. + $indicator.click(function (e) { + e.stopPropagation(); + + var index = $(this).index(); + cycleTo(index); + }); + $indicators.append($indicator); + } + }); + + if (showIndicators) { + view.append($indicators); + } + count = images.length; + + + function setupEvents() { + if (typeof window.ontouchstart !== 'undefined') { + view.on('touchstart.carousel', tap); + view.on('touchmove.carousel', drag); + view.on('touchend.carousel', release); + } + view.on('mousedown.carousel', tap); + view.on('mousemove.carousel', drag); + view.on('mouseup.carousel', release); + view.on('mouseleave.carousel', release); + view.on('click.carousel', click); + } + + function xpos(e) { + // touch event + if (e.targetTouches && (e.targetTouches.length >= 1)) { + return e.targetTouches[0].clientX; + } + + // mouse event + return e.clientX; + } + + function ypos(e) { + // touch event + if (e.targetTouches && (e.targetTouches.length >= 1)) { + return e.targetTouches[0].clientY; + } + + // mouse event + return e.clientY; + } + + function wrap(x) { + return (x >= count) ? (x % count) : (x < 0) ? wrap(count + (x % count)) : x; + } + + function scroll(x) { + // Track scrolling state + scrolling = true; + if (!view.hasClass('scrolling')) { + view.addClass('scrolling'); + } + if (scrollingTimeout != null) { + window.clearTimeout(scrollingTimeout); + } + scrollingTimeout = window.setTimeout(function() { + scrolling = false; + view.removeClass('scrolling'); + }, options.duration); + + // Start actual scroll + var i, half, delta, dir, tween, el, alignment, xTranslation; + var lastCenter = center; + + offset = (typeof x === 'number') ? x : offset; + center = Math.floor((offset + dim / 2) / dim); + delta = offset - center * dim; + dir = (delta < 0) ? 1 : -1; + tween = -dir * delta * 2 / dim; + half = count >> 1; + + if (!options.fullWidth) { + alignment = 'translateX(' + (view[0].clientWidth - item_width) / 2 + 'px) '; + alignment += 'translateY(' + (view[0].clientHeight - item_height) / 2 + 'px)'; + } else { + alignment = 'translateX(0)'; + } + + // Set indicator active + if (showIndicators) { + var diff = (center % count); + var activeIndicator = $indicators.find('.indicator-item.active'); + if (activeIndicator.index() !== diff) { + activeIndicator.removeClass('active'); + $indicators.find('.indicator-item').eq(diff).addClass('active'); + } + } + + // center + // Don't show wrapped items. + if (!noWrap || (center >= 0 && center < count)) { + el = images[wrap(center)]; + + // Add active class to center item. + if (!$(el).hasClass('active')) { + view.find('.carousel-item').removeClass('active'); + $(el).addClass('active'); + } + el.style[xform] = alignment + + ' translateX(' + (-delta / 2) + 'px)' + + ' translateX(' + (dir * options.shift * tween * i) + 'px)' + + ' translateZ(' + (options.dist * tween) + 'px)'; + el.style.zIndex = 0; + if (options.fullWidth) { tweenedOpacity = 1; } + else { tweenedOpacity = 1 - 0.2 * tween; } + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + + for (i = 1; i <= half; ++i) { + // right side + if (options.fullWidth) { + zTranslation = options.dist; + tweenedOpacity = (i === half && delta < 0) ? 1 - tween : 1; + } else { + zTranslation = options.dist * (i * 2 + tween * dir); + tweenedOpacity = 1 - 0.2 * (i * 2 + tween * dir); + } + // Don't show wrapped items. + if (!noWrap || center + i < count) { + el = images[wrap(center + i)]; + el.style[xform] = alignment + + ' translateX(' + (options.shift + (dim * i - delta) / 2) + 'px)' + + ' translateZ(' + zTranslation + 'px)'; + el.style.zIndex = -i; + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + + + // left side + if (options.fullWidth) { + zTranslation = options.dist; + tweenedOpacity = (i === half && delta > 0) ? 1 - tween : 1; + } else { + zTranslation = options.dist * (i * 2 - tween * dir); + tweenedOpacity = 1 - 0.2 * (i * 2 - tween * dir); + } + // Don't show wrapped items. + if (!noWrap || center - i >= 0) { + el = images[wrap(center - i)]; + el.style[xform] = alignment + + ' translateX(' + (-options.shift + (-dim * i - delta) / 2) + 'px)' + + ' translateZ(' + zTranslation + 'px)'; + el.style.zIndex = -i; + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + } + + // center + // Don't show wrapped items. + if (!noWrap || (center >= 0 && center < count)) { + el = images[wrap(center)]; + el.style[xform] = alignment + + ' translateX(' + (-delta / 2) + 'px)' + + ' translateX(' + (dir * options.shift * tween) + 'px)' + + ' translateZ(' + (options.dist * tween) + 'px)'; + el.style.zIndex = 0; + if (options.fullWidth) { tweenedOpacity = 1; } + else { tweenedOpacity = 1 - 0.2 * tween; } + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + + // onCycleTo callback + if (lastCenter !== center && + typeof(options.onCycleTo) === "function") { + var $curr_item = view.find('.carousel-item').eq(wrap(center)); + options.onCycleTo.call(this, $curr_item, dragged); + } + + // One time callback + if (typeof(oneTimeCallback) === "function") { + oneTimeCallback.call(this, $curr_item, dragged); + oneTimeCallback = null; + } + } + + function track() { + var now, elapsed, delta, v; + + now = Date.now(); + elapsed = now - timestamp; + timestamp = now; + delta = offset - frame; + frame = offset; + + v = 1000 * delta / (1 + elapsed); + velocity = 0.8 * v + 0.2 * velocity; + } + + function autoScroll() { + var elapsed, delta; + + if (amplitude) { + elapsed = Date.now() - timestamp; + delta = amplitude * Math.exp(-elapsed / options.duration); + if (delta > 2 || delta < -2) { + scroll(target - delta); + requestAnimationFrame(autoScroll); + } else { + scroll(target); + } + } + } + + function click(e) { + // Disable clicks if carousel was dragged. + if (dragged) { + e.preventDefault(); + e.stopPropagation(); + return false; + + } else if (!options.fullWidth) { + var clickedIndex = $(e.target).closest('.carousel-item').index(); + var diff = wrap(center) - clickedIndex; + + // Disable clicks if carousel was shifted by click + if (diff !== 0) { + e.preventDefault(); + e.stopPropagation(); + } + cycleTo(clickedIndex); + } + } + + function cycleTo(n) { + var diff = (center % count) - n; + + // Account for wraparound. + if (!noWrap) { + if (diff < 0) { + if (Math.abs(diff + count) < Math.abs(diff)) { diff += count; } + + } else if (diff > 0) { + if (Math.abs(diff - count) < diff) { diff -= count; } + } + } + + // Call prev or next accordingly. + if (diff < 0) { + view.trigger('carouselNext', [Math.abs(diff)]); + + } else if (diff > 0) { + view.trigger('carouselPrev', [diff]); + } + } + + function tap(e) { + // Fixes firefox draggable image bug + if (e.type === 'mousedown' && $(e.target).is('img')) { + e.preventDefault(); + } + pressed = true; + dragged = false; + vertical_dragged = false; + reference = xpos(e); + referenceY = ypos(e); + + velocity = amplitude = 0; + frame = offset; + timestamp = Date.now(); + clearInterval(ticker); + ticker = setInterval(track, 100); + } + + function drag(e) { + var x, delta, deltaY; + if (pressed) { + x = xpos(e); + y = ypos(e); + delta = reference - x; + deltaY = Math.abs(referenceY - y); + if (deltaY < 30 && !vertical_dragged) { + // If vertical scrolling don't allow dragging. + if (delta > 2 || delta < -2) { + dragged = true; + reference = x; + scroll(offset + delta); + } + + } else if (dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + + } else { + // Vertical scrolling. + vertical_dragged = true; + } + } + + if (dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + } + } + + function release(e) { + if (pressed) { + pressed = false; + } else { + return; + } + + clearInterval(ticker); + target = offset; + if (velocity > 10 || velocity < -10) { + amplitude = 0.9 * velocity; + target = offset + amplitude; + } + target = Math.round(target / dim) * dim; + + // No wrap of items. + if (noWrap) { + if (target >= dim * (count - 1)) { + target = dim * (count - 1); + } else if (target < 0) { + target = 0; + } + } + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + + if (dragged) { + e.preventDefault(); + e.stopPropagation(); + } + return false; + } + + xform = 'transform'; + ['webkit', 'Moz', 'O', 'ms'].every(function (prefix) { + var e = prefix + 'Transform'; + if (typeof document.body.style[e] !== 'undefined') { + xform = e; + return false; + } + return true; + }); + + + var throttledResize = Materialize.throttle(function() { + if (options.fullWidth) { + item_width = view.find('.carousel-item').first().innerWidth(); + var imageHeight = view.find('.carousel-item.active').height(); + dim = item_width * 2 + options.padding; + offset = center * 2 * item_width; + target = offset; + setCarouselHeight(true); + } else { + scroll(); + } + }, 200); + $(window) + .off('resize.carousel-'+uniqueNamespace) + .on('resize.carousel-'+uniqueNamespace, throttledResize); + + setupEvents(); + scroll(offset); + + $(this).on('carouselNext', function(e, n, callback) { + if (n === undefined) { + n = 1; + } + if (typeof(callback) === "function") { + oneTimeCallback = callback; + } + + target = (dim * Math.round(offset / dim)) + (dim * n); + if (offset !== target) { + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + } + }); + + $(this).on('carouselPrev', function(e, n, callback) { + if (n === undefined) { + n = 1; + } + if (typeof(callback) === "function") { + oneTimeCallback = callback; + } + + target = (dim * Math.round(offset / dim)) - (dim * n); + if (offset !== target) { + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + } + }); + + $(this).on('carouselSet', function(e, n, callback) { + if (n === undefined) { + n = 0; + } + if (typeof(callback) === "function") { + oneTimeCallback = callback; + } + + cycleTo(n); + }); + + }); + + + + }, + next : function(n, callback) { + $(this).trigger('carouselNext', [n, callback]); + }, + prev : function(n, callback) { + $(this).trigger('carouselPrev', [n, callback]); + }, + set : function(n, callback) { + $(this).trigger('carouselSet', [n, callback]); + }, + destroy : function() { + var uniqueNamespace = $(this).attr('data-namespace'); + $(this).removeAttr('data-namespace'); + $(this).removeClass('initialized'); + $(this).find('.indicators').remove(); + + // Remove event handlers + $(this).off('carouselNext carouselPrev carouselSet'); + $(window).off('resize.carousel-'+uniqueNamespace); + if (typeof window.ontouchstart !== 'undefined') { + $(this).off('touchstart.carousel touchmove.carousel touchend.carousel'); + } + $(this).off('mousedown.carousel mousemove.carousel mouseup.carousel mouseleave.carousel click.carousel'); + } + }; + + + $.fn.carousel = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.carousel' ); + } + }; // Plugin end +}( jQuery )); -- cgit v1.2.3