diff --git a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/IgtimiConnectionFactoryImpl.java b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/IgtimiConnectionFactoryImpl.java index 330a5d529a8..14760fad8e5 100755 --- a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/IgtimiConnectionFactoryImpl.java +++ b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/IgtimiConnectionFactoryImpl.java @@ -7,6 +7,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -498,6 +500,15 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory { URI uri = new URI((String) serverUrl); result.add(uri); } + // sort those to the front that don't do port 443 nor wss:// + Collections.sort(result, new Comparator() { + @Override + public int compare(URI o1, URI o2) { + int o1Score = (o1.toString().contains("443") ? 1 : 0) + (o1.toString().contains("wss") ? 1 : 0); + int o2Score = (o2.toString().contains("443") ? 1 : 0) + (o2.toString().contains("wss") ? 1 : 0); + return o1Score - o2Score; + } + }); return result; } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/NamedReentrantReadWriteLock.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/NamedReentrantReadWriteLock.java index 584619fd706..d465b4de2f3 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/NamedReentrantReadWriteLock.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/util/impl/NamedReentrantReadWriteLock.java @@ -11,6 +11,23 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import com.sap.sse.common.Named; +/** + * To be used in conjunction with {@link LockUtil}. Provides additional naming + * for locks which is helpful in the tracing that {@link LockUtil} provides. + * Use as in + *
+ *      NamedReentrantReadWriteLock lock = ...;
+ *      LockUtil.lockForRead(lock);
+ *      try {
+ *          // do something while holding the lock
+ *      } finally {
+ *          LockUtil.unlockAfterRead(lock);
+ *      }
+ * 
+ * + * @author Axel Uhl (d043530) + * + */ public class NamedReentrantReadWriteLock extends ReentrantReadWriteLock implements Named { private static final long serialVersionUID = 2906084982209339774L; private final String name; diff --git a/java/com.sap.sailing.gwt.ui/Home.html b/java/com.sap.sailing.gwt.ui/Home.html index 2b6cb645632..319a40e0491 100644 --- a/java/com.sap.sailing.gwt.ui/Home.html +++ b/java/com.sap.sailing.gwt.ui/Home.html @@ -26,6 +26,7 @@ + diff --git a/java/com.sap.sailing.gwt.ui/images/home/arrow-down-yellow.png b/java/com.sap.sailing.gwt.ui/images/home/arrow-down-yellow.png new file mode 100644 index 00000000000..c2db256075b Binary files /dev/null and b/java/com.sap.sailing.gwt.ui/images/home/arrow-down-yellow.png differ diff --git a/java/com.sap.sailing.gwt.ui/images/home/x_lightbox.png b/java/com.sap.sailing.gwt.ui/images/home/x_lightbox.png new file mode 100644 index 00000000000..108bc616c66 Binary files /dev/null and b/java/com.sap.sailing.gwt.ui/images/home/x_lightbox.png differ diff --git a/java/com.sap.sailing.gwt.ui/js/newhome/idangerous.swiper.js b/java/com.sap.sailing.gwt.ui/js/newhome/idangerous.swiper.js new file mode 100644 index 00000000000..7c0916c5c5f --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/js/newhome/idangerous.swiper.js @@ -0,0 +1,2803 @@ +/* + * Swiper 2.6.1 + * Mobile touch slider and framework with hardware accelerated transitions + * + * http://www.idangero.us/sliders/swiper/ + * + * Copyright 2010-2014, Vladimir Kharlampidi + * The iDangero.us + * http://www.idangero.us/ + * + * Licensed under GPL & MIT + * + * Released on: May 6, 2014 +*/ +var Swiper = function (selector, params) { + 'use strict'; + + /*========================= + A little bit dirty but required part for IE8 and old FF support + ===========================*/ + if (document.body.__defineGetter__) { + if (HTMLElement) { + var element = HTMLElement.prototype; + if (element.__defineGetter__) { + element.__defineGetter__('outerHTML', function () { return new XMLSerializer().serializeToString(this); }); + } + } + } + + if (!window.getComputedStyle) { + window.getComputedStyle = function (el, pseudo) { + this.el = el; + this.getPropertyValue = function (prop) { + var re = /(\-([a-z]){1})/g; + if (prop === 'float') prop = 'styleFloat'; + if (re.test(prop)) { + prop = prop.replace(re, function () { + return arguments[2].toUpperCase(); + }); + } + return el.currentStyle[prop] ? el.currentStyle[prop] : null; + }; + return this; + }; + } + if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (obj, start) { + for (var i = (start || 0), j = this.length; i < j; i++) { + if (this[i] === obj) { return i; } + } + return -1; + }; + } + if (!document.querySelectorAll) { + if (!window.jQuery) return; + } + function $$(selector, context) { + if (document.querySelectorAll) + return (context || document).querySelectorAll(selector); + else + return jQuery(selector, context); + } + + /*========================= + Check for correct selector + ===========================*/ + if (typeof selector === 'undefined') return; + + if (!(selector.nodeType)) { + if ($$(selector).length === 0) return; + } + + /*========================= + _this + ===========================*/ + var _this = this; + + /*========================= + Default Flags and vars + ===========================*/ + _this.touches = { + start: 0, + startX: 0, + startY: 0, + current: 0, + currentX: 0, + currentY: 0, + diff: 0, + abs: 0 + }; + _this.positions = { + start: 0, + abs: 0, + diff: 0, + current: 0 + }; + _this.times = { + start: 0, + end: 0 + }; + + _this.id = (new Date()).getTime(); + _this.container = (selector.nodeType) ? selector : $$(selector)[0]; + _this.isTouched = false; + _this.isMoved = false; + _this.activeIndex = 0; + _this.centerIndex = 0; + _this.activeLoaderIndex = 0; + _this.activeLoopIndex = 0; + _this.previousIndex = null; + _this.velocity = 0; + _this.snapGrid = []; + _this.slidesGrid = []; + _this.imagesToLoad = []; + _this.imagesLoaded = 0; + _this.wrapperLeft = 0; + _this.wrapperRight = 0; + _this.wrapperTop = 0; + _this.wrapperBottom = 0; + _this.isAndroid = navigator.userAgent.toLowerCase().indexOf('android') >= 0; + var wrapper, slideSize, wrapperSize, direction, isScrolling, containerSize; + + /*========================= + Default Parameters + ===========================*/ + var defaults = { + eventTarget: 'wrapper', // or 'container' + mode : 'horizontal', // or 'vertical' + touchRatio : 1, + speed : 300, + freeMode : false, + freeModeFluid : false, + momentumRatio: 1, + momentumBounce: true, + momentumBounceRatio: 1, + slidesPerView : 1, + slidesPerGroup : 1, + slidesPerViewFit: true, //Fit to slide when spv "auto" and slides larger than container + simulateTouch : true, + followFinger : true, + shortSwipes : true, + longSwipesRatio: 0.5, + moveStartThreshold: false, + onlyExternal : false, + createPagination : true, + pagination : false, + paginationElement: 'span', + paginationClickable: false, + paginationAsRange: true, + resistance : true, // or false or 100% + scrollContainer : false, + preventLinks : true, + preventLinksPropagation: false, + noSwiping : false, // or class + noSwipingClass : 'swiper-no-swiping', //:) + initialSlide: 0, + keyboardControl: false, + mousewheelControl : false, + mousewheelControlForceToAxis : false, + useCSS3Transforms : true, + // Autoplay + autoplay: false, + autoplayDisableOnInteraction: true, + autoplayStopOnLast: false, + //Loop mode + loop: false, + loopAdditionalSlides: 0, + // Round length values + roundLengths: false, + //Auto Height + calculateHeight: false, + cssWidthAndHeight: false, + //Images Preloader + updateOnImagesReady : true, + //Form elements + releaseFormElements : true, + //Watch for active slide, useful when use effects on different slide states + watchActiveIndex: false, + //Slides Visibility Fit + visibilityFullFit : false, + //Slides Offset + offsetPxBefore : 0, + offsetPxAfter : 0, + offsetSlidesBefore : 0, + offsetSlidesAfter : 0, + centeredSlides: false, + //Queue callbacks + queueStartCallbacks : false, + queueEndCallbacks : false, + //Auto Resize + autoResize : true, + resizeReInit : false, + //DOMAnimation + DOMAnimation : true, + //Slides Loader + loader: { + slides: [], //array with slides + slidesHTMLType: 'inner', // or 'outer' + surroundGroups: 1, //keep preloaded slides groups around view + logic: 'reload', //or 'change' + loadAllSlides: false + }, + //Namespace + slideElement: 'div', + slideClass: 'swiper-slide', + slideActiveClass: 'swiper-slide-active', + slideVisibleClass: 'swiper-slide-visible', + slideDuplicateClass: 'swiper-slide-duplicate', + wrapperClass: 'swiper-wrapper', + paginationElementClass: 'swiper-pagination-switch', + paginationActiveClass: 'swiper-active-switch', + paginationVisibleClass: 'swiper-visible-switch' + }; + params = params || {}; + for (var prop in defaults) { + if (prop in params && typeof params[prop] === 'object') { + for (var subProp in defaults[prop]) { + if (! (subProp in params[prop])) { + params[prop][subProp] = defaults[prop][subProp]; + } + } + } + else if (! (prop in params)) { + params[prop] = defaults[prop]; + } + } + _this.params = params; + if (params.scrollContainer) { + params.freeMode = true; + params.freeModeFluid = true; + } + if (params.loop) { + params.resistance = '100%'; + } + var isH = params.mode === 'horizontal'; + + /*========================= + Define Touch Events + ===========================*/ + var desktopEvents = ['mousedown', 'mousemove', 'mouseup']; + if (_this.browser.ie10) desktopEvents = ['MSPointerDown', 'MSPointerMove', 'MSPointerUp']; + if (_this.browser.ie11) desktopEvents = ['pointerdown', 'pointermove', 'pointerup']; + + _this.touchEvents = { + touchStart : _this.support.touch || !params.simulateTouch ? 'touchstart' : desktopEvents[0], + touchMove : _this.support.touch || !params.simulateTouch ? 'touchmove' : desktopEvents[1], + touchEnd : _this.support.touch || !params.simulateTouch ? 'touchend' : desktopEvents[2] + }; + + /*========================= + Wrapper + ===========================*/ + for (var i = _this.container.childNodes.length - 1; i >= 0; i--) { + if (_this.container.childNodes[i].className) { + var _wrapperClasses = _this.container.childNodes[i].className.split(/\s+/); + for (var j = 0; j < _wrapperClasses.length; j++) { + if (_wrapperClasses[j] === params.wrapperClass) { + wrapper = _this.container.childNodes[i]; + } + } + } + } + + _this.wrapper = wrapper; + /*========================= + Slide API + ===========================*/ + _this._extendSwiperSlide = function (el) { + el.append = function () { + if (params.loop) { + el.insertAfter(_this.slides.length - _this.loopedSlides); + } + else { + _this.wrapper.appendChild(el); + _this.reInit(); + } + + return el; + }; + el.prepend = function () { + if (params.loop) { + _this.wrapper.insertBefore(el, _this.slides[_this.loopedSlides]); + _this.removeLoopedSlides(); + _this.calcSlides(); + _this.createLoop(); + } + else { + _this.wrapper.insertBefore(el, _this.wrapper.firstChild); + } + _this.reInit(); + return el; + }; + el.insertAfter = function (index) { + if (typeof index === 'undefined') return false; + var beforeSlide; + + if (params.loop) { + beforeSlide = _this.slides[index + 1 + _this.loopedSlides]; + if (beforeSlide) { + _this.wrapper.insertBefore(el, beforeSlide); + } + else { + _this.wrapper.appendChild(el); + } + _this.removeLoopedSlides(); + _this.calcSlides(); + _this.createLoop(); + } + else { + beforeSlide = _this.slides[index + 1]; + _this.wrapper.insertBefore(el, beforeSlide); + } + _this.reInit(); + return el; + }; + el.clone = function () { + return _this._extendSwiperSlide(el.cloneNode(true)); + }; + el.remove = function () { + _this.wrapper.removeChild(el); + _this.reInit(); + }; + el.html = function (html) { + if (typeof html === 'undefined') { + return el.innerHTML; + } + else { + el.innerHTML = html; + return el; + } + }; + el.index = function () { + var index; + for (var i = _this.slides.length - 1; i >= 0; i--) { + if (el === _this.slides[i]) index = i; + } + return index; + }; + el.isActive = function () { + if (el.index() === _this.activeIndex) return true; + else return false; + }; + if (!el.swiperSlideDataStorage) el.swiperSlideDataStorage = {}; + el.getData = function (name) { + return el.swiperSlideDataStorage[name]; + }; + el.setData = function (name, value) { + el.swiperSlideDataStorage[name] = value; + return el; + }; + el.data = function (name, value) { + if (typeof value === 'undefined') { + return el.getAttribute('data-' + name); + } + else { + el.setAttribute('data-' + name, value); + return el; + } + }; + el.getWidth = function (outer, round) { + return _this.h.getWidth(el, outer, round); + }; + el.getHeight = function (outer, round) { + return _this.h.getHeight(el, outer, round); + }; + el.getOffset = function () { + return _this.h.getOffset(el); + }; + return el; + }; + + //Calculate information about number of slides + _this.calcSlides = function (forceCalcSlides) { + var oldNumber = _this.slides ? _this.slides.length : false; + _this.slides = []; + _this.displaySlides = []; + for (var i = 0; i < _this.wrapper.childNodes.length; i++) { + if (_this.wrapper.childNodes[i].className) { + var _className = _this.wrapper.childNodes[i].className; + var _slideClasses = _className.split(/\s+/); + for (var j = 0; j < _slideClasses.length; j++) { + if (_slideClasses[j] === params.slideClass) { + _this.slides.push(_this.wrapper.childNodes[i]); + } + } + } + } + for (i = _this.slides.length - 1; i >= 0; i--) { + _this._extendSwiperSlide(_this.slides[i]); + } + if (oldNumber === false) return; + if (oldNumber !== _this.slides.length || forceCalcSlides) { + + // Number of slides has been changed + removeSlideEvents(); + addSlideEvents(); + _this.updateActiveSlide(); + if (_this.params.pagination) _this.createPagination(); + _this.callPlugins('numberOfSlidesChanged'); + } + }; + + //Create Slide + _this.createSlide = function (html, slideClassList, el) { + slideClassList = slideClassList || _this.params.slideClass; + el = el || params.slideElement; + var newSlide = document.createElement(el); + newSlide.innerHTML = html || ''; + newSlide.className = slideClassList; + return _this._extendSwiperSlide(newSlide); + }; + + //Append Slide + _this.appendSlide = function (html, slideClassList, el) { + if (!html) return; + if (html.nodeType) { + return _this._extendSwiperSlide(html).append(); + } + else { + return _this.createSlide(html, slideClassList, el).append(); + } + }; + _this.prependSlide = function (html, slideClassList, el) { + if (!html) return; + if (html.nodeType) { + return _this._extendSwiperSlide(html).prepend(); + } + else { + return _this.createSlide(html, slideClassList, el).prepend(); + } + }; + _this.insertSlideAfter = function (index, html, slideClassList, el) { + if (typeof index === 'undefined') return false; + if (html.nodeType) { + return _this._extendSwiperSlide(html).insertAfter(index); + } + else { + return _this.createSlide(html, slideClassList, el).insertAfter(index); + } + }; + _this.removeSlide = function (index) { + if (_this.slides[index]) { + if (params.loop) { + if (!_this.slides[index + _this.loopedSlides]) return false; + _this.slides[index + _this.loopedSlides].remove(); + _this.removeLoopedSlides(); + _this.calcSlides(); + _this.createLoop(); + } + else _this.slides[index].remove(); + return true; + } + else return false; + }; + _this.removeLastSlide = function () { + if (_this.slides.length > 0) { + if (params.loop) { + _this.slides[_this.slides.length - 1 - _this.loopedSlides].remove(); + _this.removeLoopedSlides(); + _this.calcSlides(); + _this.createLoop(); + } + else _this.slides[_this.slides.length - 1].remove(); + return true; + } + else { + return false; + } + }; + _this.removeAllSlides = function () { + for (var i = _this.slides.length - 1; i >= 0; i--) { + _this.slides[i].remove(); + } + }; + _this.getSlide = function (index) { + return _this.slides[index]; + }; + _this.getLastSlide = function () { + return _this.slides[_this.slides.length - 1]; + }; + _this.getFirstSlide = function () { + return _this.slides[0]; + }; + + //Currently Active Slide + _this.activeSlide = function () { + return _this.slides[_this.activeIndex]; + }; + + /*========================= + Wrapper for Callbacks : Allows additive callbacks via function arrays + ===========================*/ + _this.fireCallback = function () { + var callback = arguments[0]; + if (Object.prototype.toString.call(callback) === '[object Array]') { + for (var i = 0; i < callback.length; i++) { + if (typeof callback[i] === 'function') { + callback[i](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); + } + } + } else if (Object.prototype.toString.call(callback) === '[object String]') { + if (params['on' + callback]) _this.fireCallback(params['on' + callback], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); + } else { + callback(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); + } + }; + function isArray(obj) { + if (Object.prototype.toString.apply(obj) === '[object Array]') return true; + return false; + } + + /** + * Allows user to add callbacks, rather than replace them + * @param callback + * @param func + * @return {*} + */ + _this.addCallback = function (callback, func) { + var _this = this, tempFunc; + if (_this.params['on' + callback]) { + if (isArray(this.params['on' + callback])) { + return this.params['on' + callback].push(func); + } else if (typeof this.params['on' + callback] === 'function') { + tempFunc = this.params['on' + callback]; + this.params['on' + callback] = []; + this.params['on' + callback].push(tempFunc); + return this.params['on' + callback].push(func); + } + } else { + this.params['on' + callback] = []; + return this.params['on' + callback].push(func); + } + }; + _this.removeCallbacks = function (callback) { + if (_this.params['on' + callback]) { + _this.params['on' + callback] = null; + } + }; + + /*========================= + Plugins API + ===========================*/ + var _plugins = []; + for (var plugin in _this.plugins) { + if (params[plugin]) { + var p = _this.plugins[plugin](_this, params[plugin]); + if (p) _plugins.push(p); + } + } + _this.callPlugins = function (method, args) { + if (!args) args = {}; + for (var i = 0; i < _plugins.length; i++) { + if (method in _plugins[i]) { + _plugins[i][method](args); + } + } + }; + + /*========================= + Windows Phone 8 Fix + ===========================*/ + if ((_this.browser.ie10 || _this.browser.ie11) && !params.onlyExternal) { + _this.wrapper.classList.add('swiper-wp8-' + (isH ? 'horizontal' : 'vertical')); + } + + /*========================= + Free Mode Class + ===========================*/ + if (params.freeMode) { + _this.container.className += ' swiper-free-mode'; + } + + /*================================================== + Init/Re-init/Resize Fix + ====================================================*/ + _this.initialized = false; + _this.init = function (force, forceCalcSlides) { + var _width = _this.h.getWidth(_this.container, false, params.roundLengths); + var _height = _this.h.getHeight(_this.container, false, params.roundLengths); + if (_width === _this.width && _height === _this.height && !force) return; + + _this.width = _width; + _this.height = _height; + + var slideWidth, slideHeight, slideMaxHeight, wrapperWidth, wrapperHeight, slideLeft; + var i; // loop index variable to avoid JSHint W004 / W038 + containerSize = isH ? _width : _height; + var wrapper = _this.wrapper; + + if (force) { + _this.calcSlides(forceCalcSlides); + } + + if (params.slidesPerView === 'auto') { + //Auto mode + var slidesWidth = 0; + var slidesHeight = 0; + + //Unset Styles + if (params.slidesOffset > 0) { + wrapper.style.paddingLeft = ''; + wrapper.style.paddingRight = ''; + wrapper.style.paddingTop = ''; + wrapper.style.paddingBottom = ''; + } + wrapper.style.width = ''; + wrapper.style.height = ''; + if (params.offsetPxBefore > 0) { + if (isH) _this.wrapperLeft = params.offsetPxBefore; + else _this.wrapperTop = params.offsetPxBefore; + } + if (params.offsetPxAfter > 0) { + if (isH) _this.wrapperRight = params.offsetPxAfter; + else _this.wrapperBottom = params.offsetPxAfter; + } + + if (params.centeredSlides) { + if (isH) { + _this.wrapperLeft = (containerSize - this.slides[0].getWidth(true, params.roundLengths)) / 2; + _this.wrapperRight = (containerSize - _this.slides[_this.slides.length - 1].getWidth(true, params.roundLengths)) / 2; + } + else { + _this.wrapperTop = (containerSize - _this.slides[0].getHeight(true, params.roundLengths)) / 2; + _this.wrapperBottom = (containerSize - _this.slides[_this.slides.length - 1].getHeight(true, params.roundLengths)) / 2; + } + } + + if (isH) { + if (_this.wrapperLeft >= 0) wrapper.style.paddingLeft = _this.wrapperLeft + 'px'; + if (_this.wrapperRight >= 0) wrapper.style.paddingRight = _this.wrapperRight + 'px'; + } + else { + if (_this.wrapperTop >= 0) wrapper.style.paddingTop = _this.wrapperTop + 'px'; + if (_this.wrapperBottom >= 0) wrapper.style.paddingBottom = _this.wrapperBottom + 'px'; + } + slideLeft = 0; + var centeredSlideLeft = 0; + _this.snapGrid = []; + _this.slidesGrid = []; + + slideMaxHeight = 0; + for (i = 0; i < _this.slides.length; i++) { + slideWidth = _this.slides[i].getWidth(true, params.roundLengths); + slideHeight = _this.slides[i].getHeight(true, params.roundLengths); + if (params.calculateHeight) { + slideMaxHeight = Math.max(slideMaxHeight, slideHeight); + } + var _slideSize = isH ? slideWidth : slideHeight; + if (params.centeredSlides) { + var nextSlideWidth = i === _this.slides.length - 1 ? 0 : _this.slides[i + 1].getWidth(true, params.roundLengths); + var nextSlideHeight = i === _this.slides.length - 1 ? 0 : _this.slides[i + 1].getHeight(true, params.roundLengths); + var nextSlideSize = isH ? nextSlideWidth : nextSlideHeight; + if (_slideSize > containerSize) { + if (params.slidesPerViewFit) { + _this.snapGrid.push(slideLeft + _this.wrapperLeft); + _this.snapGrid.push(slideLeft + _slideSize - containerSize + _this.wrapperLeft); + } + else { + for (var j = 0; j <= Math.floor(_slideSize / (containerSize + _this.wrapperLeft)); j++) { + if (j === 0) _this.snapGrid.push(slideLeft + _this.wrapperLeft); + else _this.snapGrid.push(slideLeft + _this.wrapperLeft + containerSize * j); + } + } + _this.slidesGrid.push(slideLeft + _this.wrapperLeft); + } + else { + _this.snapGrid.push(centeredSlideLeft); + _this.slidesGrid.push(centeredSlideLeft); + } + centeredSlideLeft += _slideSize / 2 + nextSlideSize / 2; + } + else { + if (_slideSize > containerSize) { + if (params.slidesPerViewFit) { + _this.snapGrid.push(slideLeft); + _this.snapGrid.push(slideLeft + _slideSize - containerSize); + } + else { + if (containerSize !== 0) { + for (var k = 0; k <= Math.floor(_slideSize / containerSize); k++) { + _this.snapGrid.push(slideLeft + containerSize * k); + } + } + else { + _this.snapGrid.push(slideLeft); + } + } + + } + else { + _this.snapGrid.push(slideLeft); + } + _this.slidesGrid.push(slideLeft); + } + + slideLeft += _slideSize; + + slidesWidth += slideWidth; + slidesHeight += slideHeight; + } + if (params.calculateHeight) _this.height = slideMaxHeight; + if (isH) { + wrapperSize = slidesWidth + _this.wrapperRight + _this.wrapperLeft; + wrapper.style.width = (slidesWidth) + 'px'; + wrapper.style.height = (_this.height) + 'px'; + } + else { + wrapperSize = slidesHeight + _this.wrapperTop + _this.wrapperBottom; + wrapper.style.width = (_this.width) + 'px'; + wrapper.style.height = (slidesHeight) + 'px'; + } + + } + else if (params.scrollContainer) { + //Scroll Container + wrapper.style.width = ''; + wrapper.style.height = ''; + wrapperWidth = _this.slides[0].getWidth(true, params.roundLengths); + wrapperHeight = _this.slides[0].getHeight(true, params.roundLengths); + wrapperSize = isH ? wrapperWidth : wrapperHeight; + wrapper.style.width = wrapperWidth + 'px'; + wrapper.style.height = wrapperHeight + 'px'; + slideSize = isH ? wrapperWidth : wrapperHeight; + + } + else { + //For usual slides + if (params.calculateHeight) { + slideMaxHeight = 0; + wrapperHeight = 0; + //ResetWrapperSize + if (!isH) _this.container.style.height = ''; + wrapper.style.height = ''; + + for (i = 0; i < _this.slides.length; i++) { + //ResetSlideSize + _this.slides[i].style.height = ''; + slideMaxHeight = Math.max(_this.slides[i].getHeight(true), slideMaxHeight); + if (!isH) wrapperHeight += _this.slides[i].getHeight(true); + } + slideHeight = slideMaxHeight; + _this.height = slideHeight; + + if (isH) wrapperHeight = slideHeight; + else { + containerSize = slideHeight; + _this.container.style.height = containerSize + 'px'; + } + } + else { + slideHeight = isH ? _this.height : _this.height / params.slidesPerView; + if (params.roundLengths) slideHeight = Math.round(slideHeight); + wrapperHeight = isH ? _this.height : _this.slides.length * slideHeight; + } + slideWidth = isH ? _this.width / params.slidesPerView : _this.width; + if (params.roundLengths) slideWidth = Math.round(slideWidth); + wrapperWidth = isH ? _this.slides.length * slideWidth : _this.width; + slideSize = isH ? slideWidth : slideHeight; + + if (params.offsetSlidesBefore > 0) { + if (isH) _this.wrapperLeft = slideSize * params.offsetSlidesBefore; + else _this.wrapperTop = slideSize * params.offsetSlidesBefore; + } + if (params.offsetSlidesAfter > 0) { + if (isH) _this.wrapperRight = slideSize * params.offsetSlidesAfter; + else _this.wrapperBottom = slideSize * params.offsetSlidesAfter; + } + if (params.offsetPxBefore > 0) { + if (isH) _this.wrapperLeft = params.offsetPxBefore; + else _this.wrapperTop = params.offsetPxBefore; + } + if (params.offsetPxAfter > 0) { + if (isH) _this.wrapperRight = params.offsetPxAfter; + else _this.wrapperBottom = params.offsetPxAfter; + } + if (params.centeredSlides) { + if (isH) { + _this.wrapperLeft = (containerSize - slideSize) / 2; + _this.wrapperRight = (containerSize - slideSize) / 2; + } + else { + _this.wrapperTop = (containerSize - slideSize) / 2; + _this.wrapperBottom = (containerSize - slideSize) / 2; + } + } + if (isH) { + if (_this.wrapperLeft > 0) wrapper.style.paddingLeft = _this.wrapperLeft + 'px'; + if (_this.wrapperRight > 0) wrapper.style.paddingRight = _this.wrapperRight + 'px'; + } + else { + if (_this.wrapperTop > 0) wrapper.style.paddingTop = _this.wrapperTop + 'px'; + if (_this.wrapperBottom > 0) wrapper.style.paddingBottom = _this.wrapperBottom + 'px'; + } + + wrapperSize = isH ? wrapperWidth + _this.wrapperRight + _this.wrapperLeft : wrapperHeight + _this.wrapperTop + _this.wrapperBottom; + if (!params.cssWidthAndHeight) { + if (parseFloat(wrapperWidth) > 0) { + wrapper.style.width = wrapperWidth + 'px'; + } + if (parseFloat(wrapperHeight) > 0) { + wrapper.style.height = wrapperHeight + 'px'; + } + } + slideLeft = 0; + _this.snapGrid = []; + _this.slidesGrid = []; + for (i = 0; i < _this.slides.length; i++) { + _this.snapGrid.push(slideLeft); + _this.slidesGrid.push(slideLeft); + slideLeft += slideSize; + if (!params.cssWidthAndHeight) { + if (parseFloat(slideWidth) > 0) { + _this.slides[i].style.width = slideWidth + 'px'; + } + if (parseFloat(slideHeight) > 0) { + _this.slides[i].style.height = slideHeight + 'px'; + } + } + } + + } + + if (!_this.initialized) { + _this.callPlugins('onFirstInit'); + if (params.onFirstInit) _this.fireCallback(params.onFirstInit, _this); + } + else { + _this.callPlugins('onInit'); + if (params.onInit) _this.fireCallback(params.onInit, _this); + } + _this.initialized = true; + }; + + _this.reInit = function (forceCalcSlides) { + _this.init(true, forceCalcSlides); + }; + + _this.resizeFix = function (reInit) { + _this.callPlugins('beforeResizeFix'); + + _this.init(params.resizeReInit || reInit); + + // swipe to active slide in fixed mode + if (!params.freeMode) { + _this.swipeTo((params.loop ? _this.activeLoopIndex : _this.activeIndex), 0, false); + // Fix autoplay + if (params.autoplay) { + if (_this.support.transitions && typeof autoplayTimeoutId !== 'undefined') { + if (typeof autoplayTimeoutId !== 'undefined') { + clearTimeout(autoplayTimeoutId); + autoplayTimeoutId = undefined; + _this.startAutoplay(); + } + } + else { + if (typeof autoplayIntervalId !== 'undefined') { + clearInterval(autoplayIntervalId); + autoplayIntervalId = undefined; + _this.startAutoplay(); + } + } + } + } + // move wrapper to the beginning in free mode + else if (_this.getWrapperTranslate() < -maxWrapperPosition()) { + _this.setWrapperTransition(0); + _this.setWrapperTranslate(-maxWrapperPosition()); + } + + _this.callPlugins('afterResizeFix'); + }; + + /*========================================== + Max and Min Positions + ============================================*/ + function maxWrapperPosition() { + var a = (wrapperSize - containerSize); + if (params.freeMode) { + a = wrapperSize - containerSize; + } + // if (params.loop) a -= containerSize; + if (params.slidesPerView > _this.slides.length && !params.centeredSlides) { + a = 0; + } + if (a < 0) a = 0; + return a; + } + + /*========================================== + Event Listeners + ============================================*/ + function initEvents() { + var bind = _this.h.addEventListener; + var eventTarget = params.eventTarget === 'wrapper' ? _this.wrapper : _this.container; + //Touch Events + if (! (_this.browser.ie10 || _this.browser.ie11)) { + if (_this.support.touch) { + bind(eventTarget, 'touchstart', onTouchStart); + bind(eventTarget, 'touchmove', onTouchMove); + bind(eventTarget, 'touchend', onTouchEnd); + } + if (params.simulateTouch) { + bind(eventTarget, 'mousedown', onTouchStart); + bind(document, 'mousemove', onTouchMove); + bind(document, 'mouseup', onTouchEnd); + } + } + else { + bind(eventTarget, _this.touchEvents.touchStart, onTouchStart); + bind(document, _this.touchEvents.touchMove, onTouchMove); + bind(document, _this.touchEvents.touchEnd, onTouchEnd); + } + + //Resize Event + if (params.autoResize) { + bind(window, 'resize', _this.resizeFix); + } + //Slide Events + addSlideEvents(); + //Mousewheel + _this._wheelEvent = false; + if (params.mousewheelControl) { + if (document.onmousewheel !== undefined) { + _this._wheelEvent = 'mousewheel'; + } + if (!_this._wheelEvent) { + try { + new WheelEvent('wheel'); + _this._wheelEvent = 'wheel'; + } catch (e) {} + } + if (!_this._wheelEvent) { + _this._wheelEvent = 'DOMMouseScroll'; + } + if (_this._wheelEvent) { + bind(_this.container, _this._wheelEvent, handleMousewheel); + } + } + + //Keyboard + function _loadImage(src) { + var image = new Image(); + image.onload = function () { + if (_this && _this.imagesLoaded !== undefined) _this.imagesLoaded++; + if (_this.imagesLoaded === _this.imagesToLoad.length) { + _this.reInit(); + if (params.onImagesReady) _this.fireCallback(params.onImagesReady, _this); + } + }; + image.src = src; + } + + if (params.keyboardControl) { + bind(document, 'keydown', handleKeyboardKeys); + } + if (params.updateOnImagesReady) { + _this.imagesToLoad = $$('img', _this.container); + + for (var i = 0; i < _this.imagesToLoad.length; i++) { + _loadImage(_this.imagesToLoad[i].getAttribute('src')); + } + } + } + + //Remove Event Listeners + _this.destroy = function () { + var unbind = _this.h.removeEventListener; + var eventTarget = params.eventTarget === 'wrapper' ? _this.wrapper : _this.container; + //Touch Events + if (! (_this.browser.ie10 || _this.browser.ie11)) { + if (_this.support.touch) { + unbind(eventTarget, 'touchstart', onTouchStart); + unbind(eventTarget, 'touchmove', onTouchMove); + unbind(eventTarget, 'touchend', onTouchEnd); + } + if (params.simulateTouch) { + unbind(eventTarget, 'mousedown', onTouchStart); + unbind(document, 'mousemove', onTouchMove); + unbind(document, 'mouseup', onTouchEnd); + } + } + else { + unbind(eventTarget, _this.touchEvents.touchStart, onTouchStart); + unbind(document, _this.touchEvents.touchMove, onTouchMove); + unbind(document, _this.touchEvents.touchEnd, onTouchEnd); + } + + //Resize Event + if (params.autoResize) { + unbind(window, 'resize', _this.resizeFix); + } + + //Init Slide Events + removeSlideEvents(); + + //Pagination + if (params.paginationClickable) { + removePaginationEvents(); + } + + //Mousewheel + if (params.mousewheelControl && _this._wheelEvent) { + unbind(_this.container, _this._wheelEvent, handleMousewheel); + } + + //Keyboard + if (params.keyboardControl) { + unbind(document, 'keydown', handleKeyboardKeys); + } + + //Stop autoplay + if (params.autoplay) { + _this.stopAutoplay(); + } + _this.callPlugins('onDestroy'); + + //Destroy variable + _this = null; + }; + + function addSlideEvents() { + var bind = _this.h.addEventListener, + i; + + //Prevent Links Events + if (params.preventLinks) { + var links = $$('a', _this.container); + for (i = 0; i < links.length; i++) { + bind(links[i], 'click', preventClick); + } + } + //Release Form Elements + if (params.releaseFormElements) { + var formElements = $$('input, textarea, select', _this.container); + for (i = 0; i < formElements.length; i++) { + bind(formElements[i], _this.touchEvents.touchStart, releaseForms, true); + } + } + + //Slide Clicks & Touches + if (params.onSlideClick) { + for (i = 0; i < _this.slides.length; i++) { + bind(_this.slides[i], 'click', slideClick); + } + } + if (params.onSlideTouch) { + for (i = 0; i < _this.slides.length; i++) { + bind(_this.slides[i], _this.touchEvents.touchStart, slideTouch); + } + } + } + function removeSlideEvents() { + var unbind = _this.h.removeEventListener, + i; + + //Slide Clicks & Touches + if (params.onSlideClick) { + for (i = 0; i < _this.slides.length; i++) { + unbind(_this.slides[i], 'click', slideClick); + } + } + if (params.onSlideTouch) { + for (i = 0; i < _this.slides.length; i++) { + unbind(_this.slides[i], _this.touchEvents.touchStart, slideTouch); + } + } + //Release Form Elements + if (params.releaseFormElements) { + var formElements = $$('input, textarea, select', _this.container); + for (i = 0; i < formElements.length; i++) { + unbind(formElements[i], _this.touchEvents.touchStart, releaseForms, true); + } + } + //Prevent Links Events + if (params.preventLinks) { + var links = $$('a', _this.container); + for (i = 0; i < links.length; i++) { + unbind(links[i], 'click', preventClick); + } + } + } + /*========================================== + Keyboard Control + ============================================*/ + function handleKeyboardKeys(e) { + var kc = e.keyCode || e.charCode; + if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) return; + if (kc === 37 || kc === 39 || kc === 38 || kc === 40) { + var inView = false; + //Check that swiper should be inside of visible area of window + var swiperOffset = _this.h.getOffset(_this.container); + var scrollLeft = _this.h.windowScroll().left; + var scrollTop = _this.h.windowScroll().top; + var windowWidth = _this.h.windowWidth(); + var windowHeight = _this.h.windowHeight(); + var swiperCoord = [ + [swiperOffset.left, swiperOffset.top], + [swiperOffset.left + _this.width, swiperOffset.top], + [swiperOffset.left, swiperOffset.top + _this.height], + [swiperOffset.left + _this.width, swiperOffset.top + _this.height] + ]; + for (var i = 0; i < swiperCoord.length; i++) { + var point = swiperCoord[i]; + if ( + point[0] >= scrollLeft && point[0] <= scrollLeft + windowWidth && + point[1] >= scrollTop && point[1] <= scrollTop + windowHeight + ) { + inView = true; + } + + } + if (!inView) return; + } + if (isH) { + if (kc === 37 || kc === 39) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + } + if (kc === 39) _this.swipeNext(); + if (kc === 37) _this.swipePrev(); + } + else { + if (kc === 38 || kc === 40) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + } + if (kc === 40) _this.swipeNext(); + if (kc === 38) _this.swipePrev(); + } + } + + _this.disableKeyboardControl = function () { + params.keyboardControl = false; + _this.h.removeEventListener(document, 'keydown', handleKeyboardKeys); + }; + + _this.enableKeyboardControl = function () { + params.keyboardControl = true; + _this.h.addEventListener(document, 'keydown', handleKeyboardKeys); + }; + + /*========================================== + Mousewheel Control + ============================================*/ + var lastScrollTime = (new Date()).getTime(); + function handleMousewheel(e) { + var we = _this._wheelEvent; + var delta = 0; + + //Opera & IE + if (e.detail) delta = -e.detail; + //WebKits + else if (we === 'mousewheel') { + if (params.mousewheelControlForceToAxis) { + if (isH) { + if (Math.abs(e.wheelDeltaX) > Math.abs(e.wheelDeltaY)) delta = e.wheelDeltaX; + else return; + } + else { + if (Math.abs(e.wheelDeltaY) > Math.abs(e.wheelDeltaX)) delta = e.wheelDeltaY; + else return; + } + } + else { + delta = e.wheelDelta; + } + } + //Old FireFox + else if (we === 'DOMMouseScroll') delta = -e.detail; + //New FireFox + else if (we === 'wheel') { + if (params.mousewheelControlForceToAxis) { + if (isH) { + if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) delta = -e.deltaX; + else return; + } + else { + if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) delta = -e.deltaY; + else return; + } + } + else { + delta = Math.abs(e.deltaX) > Math.abs(e.deltaY) ? - e.deltaX : - e.deltaY; + } + } + + if (!params.freeMode) { + if ((new Date()).getTime() - lastScrollTime > 60) { + if (delta < 0) _this.swipeNext(); + else _this.swipePrev(); + } + lastScrollTime = (new Date()).getTime(); + + } + else { + //Freemode or scrollContainer: + var position = _this.getWrapperTranslate() + delta; + + if (position > 0) position = 0; + if (position < -maxWrapperPosition()) position = -maxWrapperPosition(); + + _this.setWrapperTransition(0); + _this.setWrapperTranslate(position); + _this.updateActiveSlide(position); + + // Return page scroll on edge positions + if (position === 0 || position === -maxWrapperPosition()) return; + } + if (params.autoplay) _this.stopAutoplay(true); + + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + return false; + } + _this.disableMousewheelControl = function () { + if (!_this._wheelEvent) return false; + params.mousewheelControl = false; + _this.h.removeEventListener(_this.container, _this._wheelEvent, handleMousewheel); + return true; + }; + + _this.enableMousewheelControl = function () { + if (!_this._wheelEvent) return false; + params.mousewheelControl = true; + _this.h.addEventListener(_this.container, _this._wheelEvent, handleMousewheel); + return true; + }; + + /*========================= + Grab Cursor + ===========================*/ + if (params.grabCursor) { + var containerStyle = _this.container.style; + containerStyle.cursor = 'move'; + containerStyle.cursor = 'grab'; + containerStyle.cursor = '-moz-grab'; + containerStyle.cursor = '-webkit-grab'; + } + + /*========================= + Slides Events Handlers + ===========================*/ + + _this.allowSlideClick = true; + function slideClick(event) { + if (_this.allowSlideClick) { + setClickedSlide(event); + _this.fireCallback(params.onSlideClick, _this, event); + } + } + + function slideTouch(event) { + setClickedSlide(event); + _this.fireCallback(params.onSlideTouch, _this, event); + } + + function setClickedSlide(event) { + + // IE 6-8 support + if (!event.currentTarget) { + var element = event.srcElement; + do { + if (element.className.indexOf(params.slideClass) > -1) { + break; + } + element = element.parentNode; + } while (element); + _this.clickedSlide = element; + } + else { + _this.clickedSlide = event.currentTarget; + } + + _this.clickedSlideIndex = _this.slides.indexOf(_this.clickedSlide); + _this.clickedSlideLoopIndex = _this.clickedSlideIndex - (_this.loopedSlides || 0); + } + + _this.allowLinks = true; + function preventClick(e) { + if (!_this.allowLinks) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + if (params.preventLinksPropagation && 'stopPropagation' in e) { + e.stopPropagation(); + } + return false; + } + } + function releaseForms(e) { + if (e.stopPropagation) e.stopPropagation(); + else e.returnValue = false; + return false; + + } + + /*================================================== + Event Handlers + ====================================================*/ + var isTouchEvent = false; + var allowThresholdMove; + var allowMomentumBounce = true; + function onTouchStart(event) { + if (params.preventLinks) _this.allowLinks = true; + //Exit if slider is already was touched + if (_this.isTouched || params.onlyExternal) { + return false; + } + + if (params.noSwiping && (event.target || event.srcElement) && noSwipingSlide(event.target || event.srcElement)) return false; + allowMomentumBounce = false; + //Check For Nested Swipers + _this.isTouched = true; + isTouchEvent = event.type === 'touchstart'; + + if (!isTouchEvent || event.targetTouches.length === 1) { + _this.callPlugins('onTouchStartBegin'); + + if (!isTouchEvent && !_this.isAndroid) { + if (event.preventDefault) event.preventDefault(); + else event.returnValue = false; + } + + var pageX = isTouchEvent ? event.targetTouches[0].pageX : (event.pageX || event.clientX); + var pageY = isTouchEvent ? event.targetTouches[0].pageY : (event.pageY || event.clientY); + + //Start Touches to check the scrolling + _this.touches.startX = _this.touches.currentX = pageX; + _this.touches.startY = _this.touches.currentY = pageY; + + _this.touches.start = _this.touches.current = isH ? pageX : pageY; + + //Set Transition Time to 0 + _this.setWrapperTransition(0); + + //Get Start Translate Position + _this.positions.start = _this.positions.current = _this.getWrapperTranslate(); + + //Set Transform + _this.setWrapperTranslate(_this.positions.start); + + //TouchStartTime + _this.times.start = (new Date()).getTime(); + + //Unset Scrolling + isScrolling = undefined; + + //Set Treshold + if (params.moveStartThreshold > 0) { + allowThresholdMove = false; + } + + //CallBack + if (params.onTouchStart) _this.fireCallback(params.onTouchStart, _this, event); + _this.callPlugins('onTouchStartEnd'); + + } + } + var velocityPrevPosition, velocityPrevTime; + function onTouchMove(event) { + // If slider is not touched - exit + if (!_this.isTouched || params.onlyExternal) return; + if (isTouchEvent && event.type === 'mousemove') return; + + var pageX = isTouchEvent ? event.targetTouches[0].pageX : (event.pageX || event.clientX); + var pageY = isTouchEvent ? event.targetTouches[0].pageY : (event.pageY || event.clientY); + + //check for scrolling + if (typeof isScrolling === 'undefined' && isH) { + isScrolling = !!(isScrolling || Math.abs(pageY - _this.touches.startY) > Math.abs(pageX - _this.touches.startX)); + } + if (typeof isScrolling === 'undefined' && !isH) { + isScrolling = !!(isScrolling || Math.abs(pageY - _this.touches.startY) < Math.abs(pageX - _this.touches.startX)); + } + if (isScrolling) { + _this.isTouched = false; + return; + } + + //Check For Nested Swipers + if (event.assignedToSwiper) { + _this.isTouched = false; + return; + } + event.assignedToSwiper = true; + + //Block inner links + if (params.preventLinks) { + _this.allowLinks = false; + } + if (params.onSlideClick) { + _this.allowSlideClick = false; + } + + //Stop AutoPlay if exist + if (params.autoplay) { + _this.stopAutoplay(true); + } + if (!isTouchEvent || event.touches.length === 1) { + + //Moved Flag + if (!_this.isMoved) { + _this.callPlugins('onTouchMoveStart'); + + if (params.loop) { + _this.fixLoop(); + _this.positions.start = _this.getWrapperTranslate(); + } + if (params.onTouchMoveStart) _this.fireCallback(params.onTouchMoveStart, _this); + } + _this.isMoved = true; + + // cancel event + if (event.preventDefault) event.preventDefault(); + else event.returnValue = false; + + _this.touches.current = isH ? pageX : pageY; + + _this.positions.current = (_this.touches.current - _this.touches.start) * params.touchRatio + _this.positions.start; + + //Resistance Callbacks + if (_this.positions.current > 0 && params.onResistanceBefore) { + _this.fireCallback(params.onResistanceBefore, _this, _this.positions.current); + } + if (_this.positions.current < -maxWrapperPosition() && params.onResistanceAfter) { + _this.fireCallback(params.onResistanceAfter, _this, Math.abs(_this.positions.current + maxWrapperPosition())); + } + //Resistance + if (params.resistance && params.resistance !== '100%') { + var resistance; + //Resistance for Negative-Back sliding + if (_this.positions.current > 0) { + resistance = 1 - _this.positions.current / containerSize / 2; + if (resistance < 0.5) + _this.positions.current = (containerSize / 2); + else + _this.positions.current = _this.positions.current * resistance; + } + //Resistance for After-End Sliding + if (_this.positions.current < -maxWrapperPosition()) { + + var diff = (_this.touches.current - _this.touches.start) * params.touchRatio + (maxWrapperPosition() + _this.positions.start); + resistance = (containerSize + diff) / (containerSize); + var newPos = _this.positions.current - diff * (1 - resistance) / 2; + var stopPos = -maxWrapperPosition() - containerSize / 2; + + if (newPos < stopPos || resistance <= 0) + _this.positions.current = stopPos; + else + _this.positions.current = newPos; + } + } + if (params.resistance && params.resistance === '100%') { + //Resistance for Negative-Back sliding + if (_this.positions.current > 0 && !(params.freeMode && !params.freeModeFluid)) { + _this.positions.current = 0; + } + //Resistance for After-End Sliding + if (_this.positions.current < -maxWrapperPosition() && !(params.freeMode && !params.freeModeFluid)) { + _this.positions.current = -maxWrapperPosition(); + } + } + //Move Slides + if (!params.followFinger) return; + + if (!params.moveStartThreshold) { + _this.setWrapperTranslate(_this.positions.current); + } + else { + if (Math.abs(_this.touches.current - _this.touches.start) > params.moveStartThreshold || allowThresholdMove) { + if (!allowThresholdMove) { + allowThresholdMove = true; + _this.touches.start = _this.touches.current; + return; + } + _this.setWrapperTranslate(_this.positions.current); + } + else { + _this.positions.current = _this.positions.start; + } + } + + if (params.freeMode || params.watchActiveIndex) { + _this.updateActiveSlide(_this.positions.current); + } + + //Grab Cursor + if (params.grabCursor) { + _this.container.style.cursor = 'move'; + _this.container.style.cursor = 'grabbing'; + _this.container.style.cursor = '-moz-grabbin'; + _this.container.style.cursor = '-webkit-grabbing'; + } + //Velocity + if (!velocityPrevPosition) velocityPrevPosition = _this.touches.current; + if (!velocityPrevTime) velocityPrevTime = (new Date()).getTime(); + _this.velocity = (_this.touches.current - velocityPrevPosition) / ((new Date()).getTime() - velocityPrevTime) / 2; + if (Math.abs(_this.touches.current - velocityPrevPosition) < 2) _this.velocity = 0; + velocityPrevPosition = _this.touches.current; + velocityPrevTime = (new Date()).getTime(); + //Callbacks + _this.callPlugins('onTouchMoveEnd'); + if (params.onTouchMove) _this.fireCallback(params.onTouchMove, _this, event); + + return false; + } + } + function onTouchEnd(event) { + //Check For scrolling + if (isScrolling) { + _this.swipeReset(); + } + // If slider is not touched exit + if (params.onlyExternal || !_this.isTouched) return; + _this.isTouched = false; + + //Return Grab Cursor + if (params.grabCursor) { + _this.container.style.cursor = 'move'; + _this.container.style.cursor = 'grab'; + _this.container.style.cursor = '-moz-grab'; + _this.container.style.cursor = '-webkit-grab'; + } + + //Check for Current Position + if (!_this.positions.current && _this.positions.current !== 0) { + _this.positions.current = _this.positions.start; + } + + //For case if slider touched but not moved + if (params.followFinger) { + _this.setWrapperTranslate(_this.positions.current); + } + + // TouchEndTime + _this.times.end = (new Date()).getTime(); + + //Difference + _this.touches.diff = _this.touches.current - _this.touches.start; + _this.touches.abs = Math.abs(_this.touches.diff); + + _this.positions.diff = _this.positions.current - _this.positions.start; + _this.positions.abs = Math.abs(_this.positions.diff); + + var diff = _this.positions.diff; + var diffAbs = _this.positions.abs; + var timeDiff = _this.times.end - _this.times.start; + + if (diffAbs < 5 && (timeDiff) < 300 && _this.allowLinks === false) { + if (!params.freeMode && diffAbs !== 0) _this.swipeReset(); + //Release inner links + if (params.preventLinks) { + _this.allowLinks = true; + } + if (params.onSlideClick) { + _this.allowSlideClick = true; + } + } + + setTimeout(function () { + //Release inner links + if (params.preventLinks) { + _this.allowLinks = true; + } + if (params.onSlideClick) { + _this.allowSlideClick = true; + } + }, 100); + + var maxPosition = maxWrapperPosition(); + + //Not moved or Prevent Negative Back Sliding/After-End Sliding + if (!_this.isMoved && params.freeMode) { + _this.isMoved = false; + if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event); + _this.callPlugins('onTouchEnd'); + return; + } + if (!_this.isMoved || _this.positions.current > 0 || _this.positions.current < -maxPosition) { + _this.swipeReset(); + if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event); + _this.callPlugins('onTouchEnd'); + return; + } + + _this.isMoved = false; + + //Free Mode + if (params.freeMode) { + if (params.freeModeFluid) { + var momentumDuration = 1000 * params.momentumRatio; + var momentumDistance = _this.velocity * momentumDuration; + var newPosition = _this.positions.current + momentumDistance; + var doBounce = false; + var afterBouncePosition; + var bounceAmount = Math.abs(_this.velocity) * 20 * params.momentumBounceRatio; + if (newPosition < -maxPosition) { + if (params.momentumBounce && _this.support.transitions) { + if (newPosition + maxPosition < -bounceAmount) newPosition = -maxPosition - bounceAmount; + afterBouncePosition = -maxPosition; + doBounce = true; + allowMomentumBounce = true; + } + else newPosition = -maxPosition; + } + if (newPosition > 0) { + if (params.momentumBounce && _this.support.transitions) { + if (newPosition > bounceAmount) newPosition = bounceAmount; + afterBouncePosition = 0; + doBounce = true; + allowMomentumBounce = true; + } + else newPosition = 0; + } + //Fix duration + if (_this.velocity !== 0) momentumDuration = Math.abs((newPosition - _this.positions.current) / _this.velocity); + + _this.setWrapperTranslate(newPosition); + + _this.setWrapperTransition(momentumDuration); + + if (params.momentumBounce && doBounce) { + _this.wrapperTransitionEnd(function () { + if (!allowMomentumBounce) return; + if (params.onMomentumBounce) _this.fireCallback(params.onMomentumBounce, _this); + _this.callPlugins('onMomentumBounce'); + + _this.setWrapperTranslate(afterBouncePosition); + _this.setWrapperTransition(300); + }); + } + + _this.updateActiveSlide(newPosition); + } + if (!params.freeModeFluid || timeDiff >= 300) _this.updateActiveSlide(_this.positions.current); + + if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event); + _this.callPlugins('onTouchEnd'); + return; + } + + //Direction + direction = diff < 0 ? 'toNext' : 'toPrev'; + + //Short Touches + if (direction === 'toNext' && (timeDiff <= 300)) { + if (diffAbs < 30 || !params.shortSwipes) _this.swipeReset(); + else _this.swipeNext(true); + } + + if (direction === 'toPrev' && (timeDiff <= 300)) { + if (diffAbs < 30 || !params.shortSwipes) _this.swipeReset(); + else _this.swipePrev(true); + } + + //Long Touches + var targetSlideSize = 0; + if (params.slidesPerView === 'auto') { + //Define current slide's width + var currentPosition = Math.abs(_this.getWrapperTranslate()); + var slidesOffset = 0; + var _slideSize; + for (var i = 0; i < _this.slides.length; i++) { + _slideSize = isH ? _this.slides[i].getWidth(true, params.roundLengths) : _this.slides[i].getHeight(true, params.roundLengths); + slidesOffset += _slideSize; + if (slidesOffset > currentPosition) { + targetSlideSize = _slideSize; + break; + } + } + if (targetSlideSize > containerSize) targetSlideSize = containerSize; + } + else { + targetSlideSize = slideSize * params.slidesPerView; + } + if (direction === 'toNext' && (timeDiff > 300)) { + if (diffAbs >= targetSlideSize * params.longSwipesRatio) { + _this.swipeNext(true); + } + else { + _this.swipeReset(); + } + } + if (direction === 'toPrev' && (timeDiff > 300)) { + if (diffAbs >= targetSlideSize * params.longSwipesRatio) { + _this.swipePrev(true); + } + else { + _this.swipeReset(); + } + } + if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event); + _this.callPlugins('onTouchEnd'); + } + + + /*================================================== + noSwiping Bubble Check by Isaac Strack + ====================================================*/ + function noSwipingSlide(el) { + /*This function is specifically designed to check the parent elements for the noSwiping class, up to the wrapper. + We need to check parents because while onTouchStart bubbles, _this.isTouched is checked in onTouchStart, which stops the bubbling. + So, if a text box, for example, is the initial target, and the parent slide container has the noSwiping class, the _this.isTouched + check will never find it, and what was supposed to be noSwiping is able to be swiped. + This function will iterate up and check for the noSwiping class in parents, up through the wrapperClass.*/ + + // First we create a truthy variable, which is that swiping is allowd (noSwiping = false) + var noSwiping = false; + + // Now we iterate up (parentElements) until we reach the node with the wrapperClass. + do { + + // Each time, we check to see if there's a 'swiper-no-swiping' class (noSwipingClass). + if (el.className.indexOf(params.noSwipingClass) > -1) + { + noSwiping = true; // If there is, we set noSwiping = true; + } + + el = el.parentElement; // now we iterate up (parent node) + + } while (!noSwiping && el.parentElement && el.className.indexOf(params.wrapperClass) === -1); // also include el.parentElement truthy, just in case. + + // because we didn't check the wrapper itself, we do so now, if noSwiping is false: + if (!noSwiping && el.className.indexOf(params.wrapperClass) > -1 && el.className.indexOf(params.noSwipingClass) > -1) + noSwiping = true; // if the wrapper has the noSwipingClass, we set noSwiping = true; + + return noSwiping; + } + + function addClassToHtmlString(klass, outerHtml) { + var par = document.createElement('div'); + var child; + + par.innerHTML = outerHtml; + child = par.firstChild; + child.className += ' ' + klass; + + return child.outerHTML; + } + + + /*================================================== + Swipe Functions + ====================================================*/ + _this.swipeNext = function (internal) { + if (!internal && params.loop) _this.fixLoop(); + if (!internal && params.autoplay) _this.stopAutoplay(true); + _this.callPlugins('onSwipeNext'); + var currentPosition = _this.getWrapperTranslate(); + var newPosition = currentPosition; + if (params.slidesPerView === 'auto') { + for (var i = 0; i < _this.snapGrid.length; i++) { + if (-currentPosition >= _this.snapGrid[i] && -currentPosition < _this.snapGrid[i + 1]) { + newPosition = -_this.snapGrid[i + 1]; + break; + } + } + } + else { + var groupSize = slideSize * params.slidesPerGroup; + newPosition = -(Math.floor(Math.abs(currentPosition) / Math.floor(groupSize)) * groupSize + groupSize); + } + if (newPosition < -maxWrapperPosition()) { + newPosition = -maxWrapperPosition(); + } + if (newPosition === currentPosition) return false; + swipeToPosition(newPosition, 'next'); + return true; + }; + _this.swipePrev = function (internal) { + if (!internal && params.loop) _this.fixLoop(); + if (!internal && params.autoplay) _this.stopAutoplay(true); + _this.callPlugins('onSwipePrev'); + + var currentPosition = Math.ceil(_this.getWrapperTranslate()); + var newPosition; + if (params.slidesPerView === 'auto') { + newPosition = 0; + for (var i = 1; i < _this.snapGrid.length; i++) { + if (-currentPosition === _this.snapGrid[i]) { + newPosition = -_this.snapGrid[i - 1]; + break; + } + if (-currentPosition > _this.snapGrid[i] && -currentPosition < _this.snapGrid[i + 1]) { + newPosition = -_this.snapGrid[i]; + break; + } + } + } + else { + var groupSize = slideSize * params.slidesPerGroup; + newPosition = -(Math.ceil(-currentPosition / groupSize) - 1) * groupSize; + } + + if (newPosition > 0) newPosition = 0; + + if (newPosition === currentPosition) return false; + swipeToPosition(newPosition, 'prev'); + return true; + + }; + _this.swipeReset = function () { + _this.callPlugins('onSwipeReset'); + var currentPosition = _this.getWrapperTranslate(); + var groupSize = slideSize * params.slidesPerGroup; + var newPosition; + var maxPosition = -maxWrapperPosition(); + if (params.slidesPerView === 'auto') { + newPosition = 0; + for (var i = 0; i < _this.snapGrid.length; i++) { + if (-currentPosition === _this.snapGrid[i]) return; + if (-currentPosition >= _this.snapGrid[i] && -currentPosition < _this.snapGrid[i + 1]) { + if (_this.positions.diff > 0) newPosition = -_this.snapGrid[i + 1]; + else newPosition = -_this.snapGrid[i]; + break; + } + } + if (-currentPosition >= _this.snapGrid[_this.snapGrid.length - 1]) newPosition = -_this.snapGrid[_this.snapGrid.length - 1]; + if (currentPosition <= -maxWrapperPosition()) newPosition = -maxWrapperPosition(); + } + else { + newPosition = currentPosition < 0 ? Math.round(currentPosition / groupSize) * groupSize : 0; + } + if (params.scrollContainer) { + newPosition = currentPosition < 0 ? currentPosition : 0; + } + if (newPosition < -maxWrapperPosition()) { + newPosition = -maxWrapperPosition(); + } + if (params.scrollContainer && (containerSize > slideSize)) { + newPosition = 0; + } + + if (newPosition === currentPosition) return false; + + swipeToPosition(newPosition, 'reset'); + return true; + }; + + _this.swipeTo = function (index, speed, runCallbacks) { + index = parseInt(index, 10); + _this.callPlugins('onSwipeTo', {index: index, speed: speed}); + if (params.loop) index = index + _this.loopedSlides; + var currentPosition = _this.getWrapperTranslate(); + if (index > (_this.slides.length - 1) || index < 0) return; + var newPosition; + if (params.slidesPerView === 'auto') { + newPosition = -_this.slidesGrid[index]; + } + else { + newPosition = -index * slideSize; + } + if (newPosition < - maxWrapperPosition()) { + newPosition = - maxWrapperPosition(); + } + + if (newPosition === currentPosition) return false; + + runCallbacks = runCallbacks === false ? false : true; + swipeToPosition(newPosition, 'to', {index: index, speed: speed, runCallbacks: runCallbacks}); + return true; + }; + + function swipeToPosition(newPosition, action, toOptions) { + var speed = (action === 'to' && toOptions.speed >= 0) ? toOptions.speed : params.speed; + var timeOld = + new Date(); + + function anim() { + var timeNew = + new Date(); + var time = timeNew - timeOld; + currentPosition += animationStep * time / (1000 / 60); + condition = direction === 'toNext' ? currentPosition > newPosition : currentPosition < newPosition; + if (condition) { + _this.setWrapperTranslate(Math.round(currentPosition)); + _this._DOMAnimating = true; + window.setTimeout(function () { + anim(); + }, 1000 / 60); + } + else { + if (params.onSlideChangeEnd) { + if (action === 'to') { + if (toOptions.runCallbacks === true) _this.fireCallback(params.onSlideChangeEnd, _this); + } + else { + _this.fireCallback(params.onSlideChangeEnd, _this); + } + + } + _this.setWrapperTranslate(newPosition); + _this._DOMAnimating = false; + } + } + + if (_this.support.transitions || !params.DOMAnimation) { + _this.setWrapperTranslate(newPosition); + _this.setWrapperTransition(speed); + } + else { + //Try the DOM animation + var currentPosition = _this.getWrapperTranslate(); + var animationStep = Math.ceil((newPosition - currentPosition) / speed * (1000 / 60)); + var direction = currentPosition > newPosition ? 'toNext' : 'toPrev'; + var condition = direction === 'toNext' ? currentPosition > newPosition : currentPosition < newPosition; + if (_this._DOMAnimating) return; + + anim(); + } + + //Update Active Slide Index + _this.updateActiveSlide(newPosition); + + //Callbacks + if (params.onSlideNext && action === 'next') { + _this.fireCallback(params.onSlideNext, _this, newPosition); + } + if (params.onSlidePrev && action === 'prev') { + _this.fireCallback(params.onSlidePrev, _this, newPosition); + } + //'Reset' Callback + if (params.onSlideReset && action === 'reset') { + _this.fireCallback(params.onSlideReset, _this, newPosition); + } + + //'Next', 'Prev' and 'To' Callbacks + if (action === 'next' || action === 'prev' || (action === 'to' && toOptions.runCallbacks === true)) + slideChangeCallbacks(action); + } + /*================================================== + Transition Callbacks + ====================================================*/ + //Prevent Multiple Callbacks + _this._queueStartCallbacks = false; + _this._queueEndCallbacks = false; + function slideChangeCallbacks(direction) { + //Transition Start Callback + _this.callPlugins('onSlideChangeStart'); + if (params.onSlideChangeStart) { + if (params.queueStartCallbacks && _this.support.transitions) { + if (_this._queueStartCallbacks) return; + _this._queueStartCallbacks = true; + _this.fireCallback(params.onSlideChangeStart, _this, direction); + _this.wrapperTransitionEnd(function () { + _this._queueStartCallbacks = false; + }); + } + else _this.fireCallback(params.onSlideChangeStart, _this, direction); + } + //Transition End Callback + if (params.onSlideChangeEnd) { + if (_this.support.transitions) { + if (params.queueEndCallbacks) { + if (_this._queueEndCallbacks) return; + _this._queueEndCallbacks = true; + _this.wrapperTransitionEnd(function (swiper) { + _this.fireCallback(params.onSlideChangeEnd, swiper, direction); + }); + } + else { + _this.wrapperTransitionEnd(function (swiper) { + _this.fireCallback(params.onSlideChangeEnd, swiper, direction); + }); + } + } + else { + if (!params.DOMAnimation) { + setTimeout(function () { + _this.fireCallback(params.onSlideChangeEnd, _this, direction); + }, 10); + } + } + } + } + + /*================================================== + Update Active Slide Index + ====================================================*/ + _this.updateActiveSlide = function (position) { + if (!_this.initialized) return; + if (_this.slides.length === 0) return; + _this.previousIndex = _this.activeIndex; + if (typeof position === 'undefined') position = _this.getWrapperTranslate(); + if (position > 0) position = 0; + var i; + if (params.slidesPerView === 'auto') { + var slidesOffset = 0; + _this.activeIndex = _this.slidesGrid.indexOf(-position); + if (_this.activeIndex < 0) { + for (i = 0; i < _this.slidesGrid.length - 1; i++) { + if (-position > _this.slidesGrid[i] && -position < _this.slidesGrid[i + 1]) { + break; + } + } + var leftDistance = Math.abs(_this.slidesGrid[i] + position); + var rightDistance = Math.abs(_this.slidesGrid[i + 1] + position); + if (leftDistance <= rightDistance) _this.activeIndex = i; + else _this.activeIndex = i + 1; + } + } + else { + _this.activeIndex = Math[params.visibilityFullFit ? 'ceil' : 'round'](-position / slideSize); + } + + if (_this.activeIndex === _this.slides.length) _this.activeIndex = _this.slides.length - 1; + if (_this.activeIndex < 0) _this.activeIndex = 0; + + // Check for slide + if (!_this.slides[_this.activeIndex]) return; + + // Calc Visible slides + _this.calcVisibleSlides(position); + + // Mark visible and active slides with additonal classes + if (_this.support.classList) { + var slide; + for (i = 0; i < _this.slides.length; i++) { + slide = _this.slides[i]; + slide.classList.remove(params.slideActiveClass); + if (_this.visibleSlides.indexOf(slide) >= 0) { + slide.classList.add(params.slideVisibleClass); + } else { + slide.classList.remove(params.slideVisibleClass); + } + } + _this.slides[_this.activeIndex].classList.add(params.slideActiveClass); + } else { + var activeClassRegexp = new RegExp('\\s*' + params.slideActiveClass); + var inViewClassRegexp = new RegExp('\\s*' + params.slideVisibleClass); + + for (i = 0; i < _this.slides.length; i++) { + _this.slides[i].className = _this.slides[i].className.replace(activeClassRegexp, '').replace(inViewClassRegexp, ''); + if (_this.visibleSlides.indexOf(_this.slides[i]) >= 0) { + _this.slides[i].className += ' ' + params.slideVisibleClass; + } + } + _this.slides[_this.activeIndex].className += ' ' + params.slideActiveClass; + } + + //Update loop index + if (params.loop) { + var ls = _this.loopedSlides; + _this.activeLoopIndex = _this.activeIndex - ls; + if (_this.activeLoopIndex >= _this.slides.length - ls * 2) { + _this.activeLoopIndex = _this.slides.length - ls * 2 - _this.activeLoopIndex; + } + if (_this.activeLoopIndex < 0) { + _this.activeLoopIndex = _this.slides.length - ls * 2 + _this.activeLoopIndex; + } + if (_this.activeLoopIndex < 0) _this.activeLoopIndex = 0; + } + else { + _this.activeLoopIndex = _this.activeIndex; + } + //Update Pagination + if (params.pagination) { + _this.updatePagination(position); + } + }; + /*================================================== + Pagination + ====================================================*/ + _this.createPagination = function (firstInit) { + if (params.paginationClickable && _this.paginationButtons) { + removePaginationEvents(); + } + _this.paginationContainer = params.pagination.nodeType ? params.pagination : $$(params.pagination)[0]; + if (params.createPagination) { + var paginationHTML = ''; + var numOfSlides = _this.slides.length; + var numOfButtons = numOfSlides; + if (params.loop) numOfButtons -= _this.loopedSlides * 2; + for (var i = 0; i < numOfButtons; i++) { + paginationHTML += '<' + params.paginationElement + ' class="' + params.paginationElementClass + '">'; + } + _this.paginationContainer.innerHTML = paginationHTML; + } + _this.paginationButtons = $$('.' + params.paginationElementClass, _this.paginationContainer); + if (!firstInit) _this.updatePagination(); + _this.callPlugins('onCreatePagination'); + if (params.paginationClickable) { + addPaginationEvents(); + } + }; + function removePaginationEvents() { + var pagers = _this.paginationButtons; + if (pagers) { + for (var i = 0; i < pagers.length; i++) { + _this.h.removeEventListener(pagers[i], 'click', paginationClick); + } + } + } + function addPaginationEvents() { + var pagers = _this.paginationButtons; + if (pagers) { + for (var i = 0; i < pagers.length; i++) { + _this.h.addEventListener(pagers[i], 'click', paginationClick); + } + } + } + function paginationClick(e) { + var index; + var target = e.target || e.srcElement; + var pagers = _this.paginationButtons; + for (var i = 0; i < pagers.length; i++) { + if (target === pagers[i]) index = i; + } + _this.swipeTo(index); + } + _this.updatePagination = function (position) { + if (!params.pagination) return; + if (_this.slides.length < 1) return; + var activePagers = $$('.' + params.paginationActiveClass, _this.paginationContainer); + if (!activePagers) return; + + //Reset all Buttons' class to not active + var pagers = _this.paginationButtons; + if (pagers.length === 0) return; + for (var i = 0; i < pagers.length; i++) { + pagers[i].className = params.paginationElementClass; + } + + var indexOffset = params.loop ? _this.loopedSlides : 0; + if (params.paginationAsRange) { + if (!_this.visibleSlides) _this.calcVisibleSlides(position); + //Get Visible Indexes + var visibleIndexes = []; + var j; // lopp index - avoid JSHint W004 / W038 + for (j = 0; j < _this.visibleSlides.length; j++) { + var visIndex = _this.slides.indexOf(_this.visibleSlides[j]) - indexOffset; + + if (params.loop && visIndex < 0) { + visIndex = _this.slides.length - _this.loopedSlides * 2 + visIndex; + } + if (params.loop && visIndex >= _this.slides.length - _this.loopedSlides * 2) { + visIndex = _this.slides.length - _this.loopedSlides * 2 - visIndex; + visIndex = Math.abs(visIndex); + } + visibleIndexes.push(visIndex); + } + + for (j = 0; j < visibleIndexes.length; j++) { + if (pagers[visibleIndexes[j]]) pagers[visibleIndexes[j]].className += ' ' + params.paginationVisibleClass; + } + + if (params.loop) { + if (pagers[_this.activeLoopIndex] !== undefined) { + pagers[_this.activeLoopIndex].className += ' ' + params.paginationActiveClass; + } + } + else { + pagers[_this.activeIndex].className += ' ' + params.paginationActiveClass; + } + } + else { + if (params.loop) { + if (pagers[_this.activeLoopIndex]) pagers[_this.activeLoopIndex].className += ' ' + params.paginationActiveClass + ' ' + params.paginationVisibleClass; + } + else { + pagers[_this.activeIndex].className += ' ' + params.paginationActiveClass + ' ' + params.paginationVisibleClass; + } + } + }; + _this.calcVisibleSlides = function (position) { + var visibleSlides = []; + var _slideLeft = 0, _slideSize = 0, _slideRight = 0; + if (isH && _this.wrapperLeft > 0) position = position + _this.wrapperLeft; + if (!isH && _this.wrapperTop > 0) position = position + _this.wrapperTop; + + for (var i = 0; i < _this.slides.length; i++) { + _slideLeft += _slideSize; + if (params.slidesPerView === 'auto') + _slideSize = isH ? _this.h.getWidth(_this.slides[i], true, params.roundLengths) : _this.h.getHeight(_this.slides[i], true, params.roundLengths); + else _slideSize = slideSize; + + _slideRight = _slideLeft + _slideSize; + var isVisibile = false; + if (params.visibilityFullFit) { + if (_slideLeft >= -position && _slideRight <= -position + containerSize) isVisibile = true; + if (_slideLeft <= -position && _slideRight >= -position + containerSize) isVisibile = true; + } + else { + if (_slideRight > -position && _slideRight <= ((-position + containerSize))) isVisibile = true; + if (_slideLeft >= -position && _slideLeft < ((-position + containerSize))) isVisibile = true; + if (_slideLeft < -position && _slideRight > ((-position + containerSize))) isVisibile = true; + } + + if (isVisibile) visibleSlides.push(_this.slides[i]); + + } + if (visibleSlides.length === 0) visibleSlides = [_this.slides[_this.activeIndex]]; + + _this.visibleSlides = visibleSlides; + }; + + /*========================================== + Autoplay + ============================================*/ + var autoplayTimeoutId, autoplayIntervalId; + _this.startAutoplay = function () { + if (_this.support.transitions) { + if (typeof autoplayTimeoutId !== 'undefined') return false; + if (!params.autoplay) return; + _this.callPlugins('onAutoplayStart'); + if (params.onAutoplayStart) _this.fireCallback(params.onAutoplayStart, _this); + autoplay(); + } + else { + if (typeof autoplayIntervalId !== 'undefined') return false; + if (!params.autoplay) return; + _this.callPlugins('onAutoplayStart'); + if (params.onAutoplayStart) _this.fireCallback(params.onAutoplayStart, _this); + autoplayIntervalId = setInterval(function () { + if (params.loop) { + _this.fixLoop(); + _this.swipeNext(true); + } + else if (!_this.swipeNext(true)) { + if (!params.autoplayStopOnLast) _this.swipeTo(0); + else { + clearInterval(autoplayIntervalId); + autoplayIntervalId = undefined; + } + } + }, params.autoplay); + } + }; + _this.stopAutoplay = function (internal) { + if (_this.support.transitions) { + if (!autoplayTimeoutId) return; + if (autoplayTimeoutId) clearTimeout(autoplayTimeoutId); + autoplayTimeoutId = undefined; + if (internal && !params.autoplayDisableOnInteraction) { + _this.wrapperTransitionEnd(function () { + autoplay(); + }); + } + _this.callPlugins('onAutoplayStop'); + if (params.onAutoplayStop) _this.fireCallback(params.onAutoplayStop, _this); + } + else { + if (autoplayIntervalId) clearInterval(autoplayIntervalId); + autoplayIntervalId = undefined; + _this.callPlugins('onAutoplayStop'); + if (params.onAutoplayStop) _this.fireCallback(params.onAutoplayStop, _this); + } + }; + function autoplay() { + autoplayTimeoutId = setTimeout(function () { + if (params.loop) { + _this.fixLoop(); + _this.swipeNext(true); + } + else if (!_this.swipeNext(true)) { + if (!params.autoplayStopOnLast) _this.swipeTo(0); + else { + clearTimeout(autoplayTimeoutId); + autoplayTimeoutId = undefined; + } + } + _this.wrapperTransitionEnd(function () { + if (typeof autoplayTimeoutId !== 'undefined') autoplay(); + }); + }, params.autoplay); + } + /*================================================== + Loop + ====================================================*/ + _this.loopCreated = false; + _this.removeLoopedSlides = function () { + if (_this.loopCreated) { + for (var i = 0; i < _this.slides.length; i++) { + if (_this.slides[i].getData('looped') === true) _this.wrapper.removeChild(_this.slides[i]); + } + } + }; + + _this.createLoop = function () { + if (_this.slides.length === 0) return; + if (params.slidesPerView === 'auto') { + _this.loopedSlides = params.loopedSlides || 1; + } + else { + _this.loopedSlides = params.slidesPerView + params.loopAdditionalSlides; + } + + if (_this.loopedSlides > _this.slides.length) { + _this.loopedSlides = _this.slides.length; + } + + var slideFirstHTML = '', + slideLastHTML = '', + i; + var slidesSetFullHTML = ''; + /** + loopedSlides is too large if loopAdditionalSlides are set. + Need to divide the slides by maximum number of slides existing. + + @author Tomaz Lovrec + */ + var numSlides = _this.slides.length; + var fullSlideSets = Math.floor(_this.loopedSlides / numSlides); + var remainderSlides = _this.loopedSlides % numSlides; + // assemble full sets of slides + for (i = 0; i < (fullSlideSets * numSlides); i++) { + var j = i; + if (i >= numSlides) { + var over = Math.floor(i / numSlides); + j = i - (numSlides * over); + } + slidesSetFullHTML += _this.slides[j].outerHTML; + } + // assemble remainder slides + // assemble remainder appended to existing slides + for (i = 0; i < remainderSlides;i++) { + slideLastHTML += addClassToHtmlString(params.slideDuplicateClass, _this.slides[i].outerHTML); + } + // assemble slides that get preppended to existing slides + for (i = numSlides - remainderSlides; i < numSlides;i++) { + slideFirstHTML += addClassToHtmlString(params.slideDuplicateClass, _this.slides[i].outerHTML); + } + // assemble all slides + var slides = slideFirstHTML + slidesSetFullHTML + wrapper.innerHTML + slidesSetFullHTML + slideLastHTML; + // set the slides + wrapper.innerHTML = slides; + + _this.loopCreated = true; + _this.calcSlides(); + + //Update Looped Slides with special class + for (i = 0; i < _this.slides.length; i++) { + if (i < _this.loopedSlides || i >= _this.slides.length - _this.loopedSlides) _this.slides[i].setData('looped', true); + } + _this.callPlugins('onCreateLoop'); + + }; + + _this.fixLoop = function () { + var newIndex; + //Fix For Negative Oversliding + if (_this.activeIndex < _this.loopedSlides) { + newIndex = _this.slides.length - _this.loopedSlides * 3 + _this.activeIndex; + _this.swipeTo(newIndex, 0, false); + } + //Fix For Positive Oversliding + else if ((params.slidesPerView === 'auto' && _this.activeIndex >= _this.loopedSlides * 2) || (_this.activeIndex > _this.slides.length - params.slidesPerView * 2)) { + newIndex = -_this.slides.length + _this.activeIndex + _this.loopedSlides; + _this.swipeTo(newIndex, 0, false); + } + }; + + /*================================================== + Slides Loader + ====================================================*/ + _this.loadSlides = function () { + var slidesHTML = ''; + _this.activeLoaderIndex = 0; + var slides = params.loader.slides; + var slidesToLoad = params.loader.loadAllSlides ? slides.length : params.slidesPerView * (1 + params.loader.surroundGroups); + for (var i = 0; i < slidesToLoad; i++) { + if (params.loader.slidesHTMLType === 'outer') slidesHTML += slides[i]; + else { + slidesHTML += '<' + params.slideElement + ' class="' + params.slideClass + '" data-swiperindex="' + i + '">' + slides[i] + ''; + } + } + _this.wrapper.innerHTML = slidesHTML; + _this.calcSlides(true); + //Add permanent transitionEnd callback + if (!params.loader.loadAllSlides) { + _this.wrapperTransitionEnd(_this.reloadSlides, true); + } + }; + + _this.reloadSlides = function () { + var slides = params.loader.slides; + var newActiveIndex = parseInt(_this.activeSlide().data('swiperindex'), 10); + if (newActiveIndex < 0 || newActiveIndex > slides.length - 1) return; //<-- Exit + _this.activeLoaderIndex = newActiveIndex; + var firstIndex = Math.max(0, newActiveIndex - params.slidesPerView * params.loader.surroundGroups); + var lastIndex = Math.min(newActiveIndex + params.slidesPerView * (1 + params.loader.surroundGroups) - 1, slides.length - 1); + //Update Transforms + if (newActiveIndex > 0) { + var newTransform = -slideSize * (newActiveIndex - firstIndex); + _this.setWrapperTranslate(newTransform); + _this.setWrapperTransition(0); + } + var i; // loop index + //New Slides + if (params.loader.logic === 'reload') { + _this.wrapper.innerHTML = ''; + var slidesHTML = ''; + for (i = firstIndex; i <= lastIndex; i++) { + slidesHTML += params.loader.slidesHTMLType === 'outer' ? slides[i] : '<' + params.slideElement + ' class="' + params.slideClass + '" data-swiperindex="' + i + '">' + slides[i] + ''; + } + _this.wrapper.innerHTML = slidesHTML; + } + else { + var minExistIndex = 1000; + var maxExistIndex = 0; + + for (i = 0; i < _this.slides.length; i++) { + var index = _this.slides[i].data('swiperindex'); + if (index < firstIndex || index > lastIndex) { + _this.wrapper.removeChild(_this.slides[i]); + } + else { + minExistIndex = Math.min(index, minExistIndex); + maxExistIndex = Math.max(index, maxExistIndex); + } + } + for (i = firstIndex; i <= lastIndex; i++) { + var newSlide; + if (i < minExistIndex) { + newSlide = document.createElement(params.slideElement); + newSlide.className = params.slideClass; + newSlide.setAttribute('data-swiperindex', i); + newSlide.innerHTML = slides[i]; + _this.wrapper.insertBefore(newSlide, _this.wrapper.firstChild); + } + if (i > maxExistIndex) { + newSlide = document.createElement(params.slideElement); + newSlide.className = params.slideClass; + newSlide.setAttribute('data-swiperindex', i); + newSlide.innerHTML = slides[i]; + _this.wrapper.appendChild(newSlide); + } + } + } + //reInit + _this.reInit(true); + }; + + /*================================================== + Make Swiper + ====================================================*/ + function makeSwiper() { + _this.calcSlides(); + if (params.loader.slides.length > 0 && _this.slides.length === 0) { + _this.loadSlides(); + } + if (params.loop) { + _this.createLoop(); + } + _this.init(); + initEvents(); + if (params.pagination) { + _this.createPagination(true); + } + + if (params.loop || params.initialSlide > 0) { + _this.swipeTo(params.initialSlide, 0, false); + } + else { + _this.updateActiveSlide(0); + } + if (params.autoplay) { + _this.startAutoplay(); + } + /** + * Set center slide index. + * + * @author Tomaz Lovrec + */ + _this.centerIndex = _this.activeIndex; + + // Callbacks + if (params.onSwiperCreated) _this.fireCallback(params.onSwiperCreated, _this); + _this.callPlugins('onSwiperCreated'); + } + + makeSwiper(); +}; + +Swiper.prototype = { + plugins : {}, + + /*================================================== + Wrapper Operations + ====================================================*/ + wrapperTransitionEnd : function (callback, permanent) { + 'use strict'; + var a = this, + el = a.wrapper, + events = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'], + i; + + function fireCallBack() { + callback(a); + if (a.params.queueEndCallbacks) a._queueEndCallbacks = false; + if (!permanent) { + for (i = 0; i < events.length; i++) { + a.h.removeEventListener(el, events[i], fireCallBack); + } + } + } + + if (callback) { + for (i = 0; i < events.length; i++) { + a.h.addEventListener(el, events[i], fireCallBack); + } + } + }, + + getWrapperTranslate : function (axis) { + 'use strict'; + var el = this.wrapper, + matrix, curTransform, curStyle, transformMatrix; + + // automatic axis detection + if (typeof axis === 'undefined') { + axis = this.params.mode === 'horizontal' ? 'x' : 'y'; + } + + if (this.support.transforms && this.params.useCSS3Transforms) { + curStyle = window.getComputedStyle(el, null); + if (window.WebKitCSSMatrix) { + // Some old versions of Webkit choke when 'none' is passed; pass + // empty string instead in this case + transformMatrix = new WebKitCSSMatrix(curStyle.webkitTransform === 'none' ? '' : curStyle.webkitTransform); + } + else { + transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,'); + matrix = transformMatrix.toString().split(','); + } + + if (axis === 'x') { + //Latest Chrome and webkits Fix + if (window.WebKitCSSMatrix) + curTransform = transformMatrix.m41; + //Crazy IE10 Matrix + else if (matrix.length === 16) + curTransform = parseFloat(matrix[12]); + //Normal Browsers + else + curTransform = parseFloat(matrix[4]); + } + if (axis === 'y') { + //Latest Chrome and webkits Fix + if (window.WebKitCSSMatrix) + curTransform = transformMatrix.m42; + //Crazy IE10 Matrix + else if (matrix.length === 16) + curTransform = parseFloat(matrix[13]); + //Normal Browsers + else + curTransform = parseFloat(matrix[5]); + } + } + else { + if (axis === 'x') curTransform = parseFloat(el.style.left, 10) || 0; + if (axis === 'y') curTransform = parseFloat(el.style.top, 10) || 0; + } + return curTransform || 0; + }, + + setWrapperTranslate : function (x, y, z) { + 'use strict'; + var es = this.wrapper.style, + coords = {x: 0, y: 0, z: 0}, + translate; + + // passed all coordinates + if (arguments.length === 3) { + coords.x = x; + coords.y = y; + coords.z = z; + } + + // passed one coordinate and optional axis + else { + if (typeof y === 'undefined') { + y = this.params.mode === 'horizontal' ? 'x' : 'y'; + } + coords[y] = x; + } + + if (this.support.transforms && this.params.useCSS3Transforms) { + translate = this.support.transforms3d ? 'translate3d(' + coords.x + 'px, ' + coords.y + 'px, ' + coords.z + 'px)' : 'translate(' + coords.x + 'px, ' + coords.y + 'px)'; + es.webkitTransform = es.MsTransform = es.msTransform = es.MozTransform = es.OTransform = es.transform = translate; + } + else { + es.left = coords.x + 'px'; + es.top = coords.y + 'px'; + } + this.callPlugins('onSetWrapperTransform', coords); + if (this.params.onSetWrapperTransform) this.fireCallback(this.params.onSetWrapperTransform, this, coords); + }, + + setWrapperTransition : function (duration) { + 'use strict'; + var es = this.wrapper.style; + es.webkitTransitionDuration = es.MsTransitionDuration = es.msTransitionDuration = es.MozTransitionDuration = es.OTransitionDuration = es.transitionDuration = (duration / 1000) + 's'; + this.callPlugins('onSetWrapperTransition', {duration: duration}); + if (this.params.onSetWrapperTransition) this.fireCallback(this.params.onSetWrapperTransition, this, duration); + + }, + + /*================================================== + Helpers + ====================================================*/ + h : { + getWidth: function (el, outer, round) { + 'use strict'; + var width = window.getComputedStyle(el, null).getPropertyValue('width'); + var returnWidth = parseFloat(width); + //IE Fixes + if (isNaN(returnWidth) || width.indexOf('%') > 0) { + returnWidth = el.offsetWidth - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-left')) - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-right')); + } + if (outer) returnWidth += parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-left')) + parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-right')); + if (round) return Math.round(returnWidth); + else return returnWidth; + }, + getHeight: function (el, outer, round) { + 'use strict'; + if (outer) return el.offsetHeight; + + var height = window.getComputedStyle(el, null).getPropertyValue('height'); + var returnHeight = parseFloat(height); + //IE Fixes + if (isNaN(returnHeight) || height.indexOf('%') > 0) { + returnHeight = el.offsetHeight - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-top')) - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-bottom')); + } + if (outer) returnHeight += parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-top')) + parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-bottom')); + if (round) return Math.round(returnHeight); + else return returnHeight; + }, + getOffset: function (el) { + 'use strict'; + var box = el.getBoundingClientRect(); + var body = document.body; + var clientTop = el.clientTop || body.clientTop || 0; + var clientLeft = el.clientLeft || body.clientLeft || 0; + var scrollTop = window.pageYOffset || el.scrollTop; + var scrollLeft = window.pageXOffset || el.scrollLeft; + if (document.documentElement && !window.pageYOffset) { + //IE7-8 + scrollTop = document.documentElement.scrollTop; + scrollLeft = document.documentElement.scrollLeft; + } + return { + top: box.top + scrollTop - clientTop, + left: box.left + scrollLeft - clientLeft + }; + }, + windowWidth : function () { + 'use strict'; + if (window.innerWidth) return window.innerWidth; + else if (document.documentElement && document.documentElement.clientWidth) return document.documentElement.clientWidth; + }, + windowHeight : function () { + 'use strict'; + if (window.innerHeight) return window.innerHeight; + else if (document.documentElement && document.documentElement.clientHeight) return document.documentElement.clientHeight; + }, + windowScroll : function () { + 'use strict'; + if (typeof pageYOffset !== 'undefined') { + return { + left: window.pageXOffset, + top: window.pageYOffset + }; + } + else if (document.documentElement) { + return { + left: document.documentElement.scrollLeft, + top: document.documentElement.scrollTop + }; + } + }, + + addEventListener : function (el, event, listener, useCapture) { + 'use strict'; + if (typeof useCapture === 'undefined') { + useCapture = false; + } + + if (el.addEventListener) { + el.addEventListener(event, listener, useCapture); + } + else if (el.attachEvent) { + el.attachEvent('on' + event, listener); + } + }, + + removeEventListener : function (el, event, listener, useCapture) { + 'use strict'; + if (typeof useCapture === 'undefined') { + useCapture = false; + } + + if (el.removeEventListener) { + el.removeEventListener(event, listener, useCapture); + } + else if (el.detachEvent) { + el.detachEvent('on' + event, listener); + } + } + }, + setTransform : function (el, transform) { + 'use strict'; + var es = el.style; + es.webkitTransform = es.MsTransform = es.msTransform = es.MozTransform = es.OTransform = es.transform = transform; + }, + setTranslate : function (el, translate) { + 'use strict'; + var es = el.style; + var pos = { + x : translate.x || 0, + y : translate.y || 0, + z : translate.z || 0 + }; + var transformString = this.support.transforms3d ? 'translate3d(' + (pos.x) + 'px,' + (pos.y) + 'px,' + (pos.z) + 'px)' : 'translate(' + (pos.x) + 'px,' + (pos.y) + 'px)'; + es.webkitTransform = es.MsTransform = es.msTransform = es.MozTransform = es.OTransform = es.transform = transformString; + if (!this.support.transforms) { + es.left = pos.x + 'px'; + es.top = pos.y + 'px'; + } + }, + setTransition : function (el, duration) { + 'use strict'; + var es = el.style; + es.webkitTransitionDuration = es.MsTransitionDuration = es.msTransitionDuration = es.MozTransitionDuration = es.OTransitionDuration = es.transitionDuration = duration + 'ms'; + }, + /*================================================== + Feature Detection + ====================================================*/ + support: { + + touch : (window.Modernizr && Modernizr.touch === true) || (function () { + 'use strict'; + return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch); + })(), + + transforms3d : (window.Modernizr && Modernizr.csstransforms3d === true) || (function () { + 'use strict'; + var div = document.createElement('div').style; + return ('webkitPerspective' in div || 'MozPerspective' in div || 'OPerspective' in div || 'MsPerspective' in div || 'perspective' in div); + })(), + + transforms : (window.Modernizr && Modernizr.csstransforms === true) || (function () { + 'use strict'; + var div = document.createElement('div').style; + return ('transform' in div || 'WebkitTransform' in div || 'MozTransform' in div || 'msTransform' in div || 'MsTransform' in div || 'OTransform' in div); + })(), + + transitions : (window.Modernizr && Modernizr.csstransitions === true) || (function () { + 'use strict'; + var div = document.createElement('div').style; + return ('transition' in div || 'WebkitTransition' in div || 'MozTransition' in div || 'msTransition' in div || 'MsTransition' in div || 'OTransition' in div); + })(), + + classList : (function () { + 'use strict'; + var div = document.createElement('div').style; + return 'classList' in div; + })() + }, + + browser : { + + ie8 : (function () { + 'use strict'; + var rv = -1; // Return value assumes failure. + if (navigator.appName === 'Microsoft Internet Explorer') { + var ua = navigator.userAgent; + var re = new RegExp(/MSIE ([0-9]{1,}[\.0-9]{0,})/); + if (re.exec(ua) !== null) + rv = parseFloat(RegExp.$1); + } + return rv !== -1 && rv < 9; + })(), + + ie10 : window.navigator.msPointerEnabled, + ie11 : window.navigator.pointerEnabled + } +}; + +/*========================= + jQuery & Zepto Plugins + ===========================*/ +if (window.jQuery || window.Zepto) { + (function ($) { + 'use strict'; + $.fn.swiper = function (params) { + var s = new Swiper($(this)[0], params); + $(this).data('swiper', s); + return s; + }; + })(window.jQuery || window.Zepto); +} + +// component +if (typeof(module) !== 'undefined') +{ + module.exports = Swiper; +} + +// requirejs support +if (typeof define === 'function' && define.amd) { + define([], function () { + 'use strict'; + return Swiper; + }); +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/AbstractBasePlace.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/AbstractBasePlace.java new file mode 100644 index 00000000000..5a650d9c322 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/AbstractBasePlace.java @@ -0,0 +1,92 @@ +package com.sap.sailing.gwt.home.client; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import com.google.gwt.place.shared.Place; + +/** + * An abstract Place which is able to manage and parse place parameters. + * @author Frank + * + */ +public abstract class AbstractBasePlace extends Place { + private static final Logger logger = Logger.getLogger(AbstractBasePlace.class.getName()); + private static final String VALIDATE_TOKENS_MESSAGE_PREFIX = "Missing token(s): "; + + private String placeParametersAsToken; + private Map params = new HashMap(); + + public AbstractBasePlace(String... paramKeysAndValues) { + if (paramKeysAndValues.length % 2 == 0) { + StringBuilder stringBuilder = new StringBuilder(); + + for (int i = 0; i < paramKeysAndValues.length; i++) { + String paramName = paramKeysAndValues[i++]; + String paramValue = paramKeysAndValues[i]; + // for now we don't add 'null' parameters + if(paramValue != null) { + params.put(paramName, paramValue); + if(stringBuilder.length() > 0) { + stringBuilder.append("&"); + } + stringBuilder.append(paramName + "=" + paramValue); + } + } + + placeParametersAsToken = stringBuilder.toString(); + } else { + logger.warning("Invalid number of arguments received! Must be key,value,key,value ... ignoring arguments"); + } + } + + public AbstractBasePlace(String url) { + if (url != null && !url.isEmpty()) { + this.placeParametersAsToken = url; + + List list = Arrays.asList(url.split("&")); + + if (list == null || list.size() < 1) { + logger.warning("Token empty, no-op"); + return; + } + + for (String listItem : list) { + List nvPair = Arrays.asList(listItem.split("=")); + if (nvPair == null || nvPair.size() != 2) { + logger.warning("Invalid parameters"); + continue; + } + params.put(nvPair.get(0), nvPair.get(1)); + } + } + } + + protected void validate(String... paramNames) { + StringBuffer message = new StringBuffer(VALIDATE_TOKENS_MESSAGE_PREFIX); + + for (String name : paramNames) { + if (!params.containsKey(name)) + message.append(name + " "); + } + + if (!message.toString().equals(VALIDATE_TOKENS_MESSAGE_PREFIX)) { + logger.warning(message.toString()); + } + } + + public String getParametersAsToken() { + return placeParametersAsToken; + } + + public String getParameter(String name) { + return params.get(name); + } + + public boolean hasParameter(String name) { + return params.containsKey(name); + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/HomeResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/HomeResources.java index 8f8ebfb6f57..9bdbf18c858 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/HomeResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/HomeResources.java @@ -42,6 +42,18 @@ public interface HomeResources extends ClientBundle { String mainsection_header(); String mainsection_header_title(); String mainsection_navigation(); + + String lightbox(); + String lightbox_overlay(); + String lightbox_overlayhidden(); + String lightbox_content(); + String lightbox_contenthidden(); + String lightbox_content_enlargedimage(); + String lightbox_content_enlargedimage_caption(); + String lightbox_content_enlargedimage_close(); + String lightbox_data(); + String lightbox_photo(); + String lightbox_item(); } @Shared diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/PlaceNavigator.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/PlaceNavigator.java index 94d71ab819a..e0cff6053bb 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/PlaceNavigator.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/PlaceNavigator.java @@ -2,7 +2,8 @@ package com.sap.sailing.gwt.home.client.app; public interface PlaceNavigator { void goToHome(); - void goToEvent(String eventUuidAsString); + void goToEvent(String eventUuidAsString, String baseUrl); + void goToRegattaOfEvent(String eventUuidAsString, String regattaIdAsNameString, String baseUrl); void goToSearchResult(String searchQuery); void goToEvents(); void goToAboutUs(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/PlaceNavigatorImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/PlaceNavigatorImpl.java index 82f444748ff..fa589792ca5 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/PlaceNavigatorImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/PlaceNavigatorImpl.java @@ -1,6 +1,9 @@ package com.sap.sailing.gwt.home.client.app; +import com.google.gwt.place.shared.Place; import com.google.gwt.place.shared.PlaceController; +import com.google.gwt.place.shared.PlaceTokenizer; +import com.google.gwt.user.client.Window; import com.sap.sailing.gwt.home.client.place.aboutus.AboutUsPlace; import com.sap.sailing.gwt.home.client.place.contact.ContactPlace; import com.sap.sailing.gwt.home.client.place.event.EventPlace; @@ -12,6 +15,7 @@ import com.sap.sailing.gwt.home.client.place.start.StartPlace; public class PlaceNavigatorImpl implements PlaceNavigator { private final PlaceController placeController; + private final static String SAPSAILING_DOMAIN = "www.sapsailing.com"; protected PlaceNavigatorImpl(PlaceController placeController) { super(); @@ -20,42 +24,79 @@ public class PlaceNavigatorImpl implements PlaceNavigator { @Override public void goToHome() { - placeController.goTo(new StartPlace()); + gotoPlace(new StartPlace(), new StartPlace.Tokenizer()); } @Override - public void goToEvent(String eventUuidAsString) { - placeController.goTo(new EventPlace(eventUuidAsString)); + public void goToEvent(String eventUuidAsString, String baseUrl) { + EventPlace eventPlace = new EventPlace(eventUuidAsString); + if(isLocationOnLocalhost() || baseUrl.contains(SAPSAILING_DOMAIN)) { + placeController.goTo(eventPlace); + } else { + String remoteEventUrl = buildRemotePlaceUrl(baseUrl, eventPlace, new EventPlace.Tokenizer()); + Window.Location.replace(remoteEventUrl); + } + } + + @Override + public void goToRegattaOfEvent(String eventUuidAsString, String leaderboardIdAsNameString, String baseUrl) { + EventPlace eventPlace = new EventPlace(eventUuidAsString, leaderboardIdAsNameString); + if(isLocationOnLocalhost() || baseUrl.contains(SAPSAILING_DOMAIN)) { + placeController.goTo(eventPlace); + } else { + String remoteEventUrl = buildRemotePlaceUrl(baseUrl, eventPlace, new EventPlace.Tokenizer()); + Window.Location.replace(remoteEventUrl); + } } @Override public void goToSearchResult(String searchQuery) { - placeController.goTo(new SearchResultPlace(searchQuery)); + gotoPlace(new SearchResultPlace(searchQuery), new SearchResultPlace.Tokenizer()); } @Override public void goToEvents() { - placeController.goTo(new EventsPlace()); + gotoPlace(new EventsPlace(), new EventsPlace.Tokenizer()); } @Override public void goToAboutUs() { - placeController.goTo(new AboutUsPlace()); + gotoPlace(new AboutUsPlace(), new AboutUsPlace.Tokenizer()); } @Override public void goToContact() { - placeController.goTo(new ContactPlace()); + gotoPlace(new ContactPlace(), new ContactPlace.Tokenizer()); } @Override public void goToSolutions() { - placeController.goTo(new SolutionsPlace()); + gotoPlace(new SolutionsPlace(), new SolutionsPlace.Tokenizer()); } @Override public void goToSponsoring() { - placeController.goTo(new SponsoringPlace()); + gotoPlace(new SponsoringPlace(), new SponsoringPlace.Tokenizer()); } + private void gotoPlace(T destinationPlace, PlaceTokenizer tokenizer) { + if(isLocationOnLocalhost() || isLocationOnSapSailingCom()) { + placeController.goTo(destinationPlace); + } else { + String homeUrl = buildRemotePlaceUrl("http://" + SAPSAILING_DOMAIN, destinationPlace, tokenizer); + Window.Location.replace(homeUrl); + } + } + + private String buildRemotePlaceUrl(String baseUrl, T destinationPlace, PlaceTokenizer tokenizer) { + return baseUrl + "/gwt/Home.html#" + destinationPlace.getClass().getSimpleName() + ":" + tokenizer.getToken(destinationPlace); + } + + private boolean isLocationOnSapSailingCom() { + return Window.Location.getHostName().contains(SAPSAILING_DOMAIN); + } + + private boolean isLocationOnLocalhost() { + return Window.Location.getHostName().contains("localhost") || Window.Location.getHostName().contains("127.0.0.1"); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/SmartphoneApplicationClientFactory.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/SmartphoneApplicationClientFactory.java index 27fff443d4b..ab5e46d4bf8 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/SmartphoneApplicationClientFactory.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/SmartphoneApplicationClientFactory.java @@ -1,19 +1,28 @@ package com.sap.sailing.gwt.home.client.app; +import java.util.List; + import com.google.gwt.event.shared.SimpleEventBus; import com.google.gwt.place.shared.PlaceController; import com.google.web.bindery.event.shared.EventBus; import com.sap.sailing.gwt.home.client.place.event.EventView; +import com.sap.sailing.gwt.home.client.place.event.TabletAndDesktopEventView; import com.sap.sailing.gwt.home.client.place.events.EventsActivity; import com.sap.sailing.gwt.home.client.place.events.EventsView; +import com.sap.sailing.gwt.home.client.place.events.TabletAndDesktopEventsView; import com.sap.sailing.gwt.home.client.place.searchresult.SearchResultView; +import com.sap.sailing.gwt.home.client.place.searchresult.TabletAndDesktopSearchResultView; import com.sap.sailing.gwt.home.client.place.solutions.SolutionsActivity; import com.sap.sailing.gwt.home.client.place.solutions.SolutionsView; +import com.sap.sailing.gwt.home.client.place.solutions.TabletAndDesktopSolutionsView; import com.sap.sailing.gwt.home.client.place.sponsoring.SponsoringActivity; import com.sap.sailing.gwt.home.client.place.sponsoring.SponsoringView; -import com.sap.sailing.gwt.home.client.place.start.SmartphoneStartView; +import com.sap.sailing.gwt.home.client.place.sponsoring.TabletAndDesktopSponsoringView; import com.sap.sailing.gwt.home.client.place.start.StartView; +import com.sap.sailing.gwt.home.client.place.start.TabletAndDesktopStartView; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; +import com.sap.sse.gwt.client.player.Timer; public class SmartphoneApplicationClientFactory extends AbstractApplicationClientFactory implements ApplicationClientFactory { @@ -30,32 +39,33 @@ public class SmartphoneApplicationClientFactory extends AbstractApplicationClien } @Override - public EventView createEventView(EventDTO event) { - return null; + public EventView createEventView(EventDTO event, List raceGroups, String leaderboardName, Timer timerForClientServerOffset) { + return new TabletAndDesktopEventView(getSailingService(), event, raceGroups, leaderboardName, timerForClientServerOffset); } @Override public EventsView createEventsView(EventsActivity activity) { - return null; + return new TabletAndDesktopEventsView(getPlaceNavigator()); } @Override public StartView createStartView() { - return new SmartphoneStartView(getPlaceNavigator()); + return new TabletAndDesktopStartView(getPlaceNavigator()); +// return new SmartphoneStartView(getPlaceNavigator()); } @Override public SponsoringView createSponsoringView(SponsoringActivity activity) { - return null; + return new TabletAndDesktopSponsoringView(); } @Override public SolutionsView createSolutionsView(SolutionsActivity activity) { - return null; + return new TabletAndDesktopSolutionsView(); } @Override public SearchResultView createSearchResultView() { - return null; + return new TabletAndDesktopSearchResultView(getPlaceNavigator(), getEventBus()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/TabletAndDesktopApplicationClientFactory.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/TabletAndDesktopApplicationClientFactory.java index 4b84d46c542..c58a34f6f62 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/TabletAndDesktopApplicationClientFactory.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/app/TabletAndDesktopApplicationClientFactory.java @@ -1,5 +1,7 @@ package com.sap.sailing.gwt.home.client.app; +import java.util.List; + import com.google.gwt.event.shared.SimpleEventBus; import com.google.gwt.place.shared.PlaceController; import com.google.web.bindery.event.shared.EventBus; @@ -19,6 +21,8 @@ import com.sap.sailing.gwt.home.client.place.sponsoring.TabletAndDesktopSponsori import com.sap.sailing.gwt.home.client.place.start.StartView; import com.sap.sailing.gwt.home.client.place.start.TabletAndDesktopStartView; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; +import com.sap.sse.gwt.client.player.Timer; public class TabletAndDesktopApplicationClientFactory extends AbstractApplicationClientFactory implements ApplicationClientFactory { @@ -35,8 +39,8 @@ public class TabletAndDesktopApplicationClientFactory extends AbstractApplicatio } @Override - public EventView createEventView(EventDTO event) { - return new TabletAndDesktopEventView(event); + public EventView createEventView(EventDTO event, List raceGroups, String leaderboardName, Timer timerForClientServerOffset) { + return new TabletAndDesktopEventView(getSailingService(), event, raceGroups, leaderboardName, timerForClientServerOffset); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages.java index bc5b127d2a3..8591adb04ed 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages.java @@ -20,6 +20,8 @@ public interface TextMessages extends Messages { String countdownMinutes(); String countdownSeconds(); String live(); + String finished(); + String watchNow(); String lastUpdate(); String leaderBoard(); String boxNewsUpdateMoreLink(); @@ -39,9 +41,19 @@ public interface TextMessages extends Messages { String eventHeaderOverview(); String eventHeaderRaces(); String eventHeaderRegattas(); - String eventHeaderSchedule(); + String seriesHeaderOverview(); + String seriesHeaderUpcoming(); + String seriesHeaderRecent(); + String seriesHeaderLeaderboard(); + String seriesOverviewHeaderRecent(); + String seriesOverviewReadMore(); + String eventsOverviewRecentEvents(); + String eventsOverviewRecentCountries(); + String eventsOverviewRecentSailors(); + String eventsOverviewRecentTrackedRaces(); String eventResultsHeadline(); String eventResultsBoatClassesDropDown(); + String eventOverviewMoreEvents(); String eventOverviewRecentEvents(); String eventOverviewUpcomingDate(); String eventOverviewUpcomingEvent(); @@ -51,7 +63,8 @@ public interface TextMessages extends Messages { String eventOverviewUpcomingTeaser(); String eventQuickfinderTitle(); String eventRegattaHeaderLeaderboard(); - String eventRegattaHeaderRaceSchedule(); + String eventRegattaHeaderRaceRaces(); + String eventRegattaListAllBoatClasses(); String eventRegattaLeaderboardCompetitor(); String eventRegattaLeaderboardExtendLeaderboard(); String eventRegattaLeaderboardFinishedMessage(); @@ -59,11 +72,22 @@ public interface TextMessages extends Messages { String eventRegattaLeaderboardName(); String eventRegattaLeaderboardRegattaRank(); String eventRegattaLeaderboardTotalPoints(); + String eventRegattaRaceWatch(); + String eventRegattaRaceAnalyse(); + String eventRegattaRaceNotTracked(); + String eventRegattaRaceFinished(); + String eventRegattaRaceStarted(); + String eventRegattaRaceScheduled(); + String eventRegattaRacesLegendGps(); + String eventRegattaRacesLegendWind(); + String eventRegattaRacesLegendVideo(); + String eventRegattaRacesLegendAudio(); String eventSponsorsTitle(); String footerCopyright(); String footerLanguage(); String footerLegal(); String footerPrivacy(); + String footerFeedback(); String headerEvents(); String headerHome(); String headerLogo(); @@ -80,7 +104,6 @@ public interface TextMessages extends Messages { String leaderboardQuickAccessLabel(); String mainEventShowAll(); String mainEventTitle(); - String mainMediaShowMore(); String mainMediaSubtitle(); String mainMediaTitle(); String mainMediaVideosSubtitle(); @@ -88,12 +111,16 @@ public interface TextMessages extends Messages { String mainSponsorsReadMore(); String mediaTeaserPhotosTitle(); String mediaTeaserVideosTitle(); - String regattaIntroContentCompetitors(); - String regattaIntroContentCourse(); - String regattaIntroContentRaces(); - String regattaIntroContentScoring(); - String regattaIntroContentMethod(); - String regattaIntroContentWindAvg(); + String regattaCompetitors(); + String regattaRaces(); + String regattaTracked(); + String regattaRegattaStarts(); + String regattaPts(); + String regattaCourse(); + String regattaArea(); + String regattaFinishedAt(); + String regattaScheduledAt(); + String regattaStartedAt(); String regattasResultsTitle(); String searchResultHeaderButton(); String searchResultHeaderLabel(); @@ -105,20 +132,26 @@ public interface TextMessages extends Messages { String searchResultSortNewest(); String searchResultSortOldest(); String searchResultSortRelevance(); + String searchResultCount(); String sharingEmail(); String sharingFacebook(); String sharingTwitter(); String socialFooterShare(); String socialFooterTitle(); + String solutionsSAPNav(); String solutionsSAPHeadline(); String solutionsSAPText1(); String solutionsSAPText2(); + String solutionsRaceNav(); String solutionsRaceHeadline(); String solutionsRaceText(); + String solutionsPostNav(); String solutionsPostHeadline(); String solutionsPostText(); + String solutionsTrainingNav(); String solutionsTrainingHeadline(); String solutionsTrainingText(); + String solutionsSimulatorNav(); String solutionsSimulatorHeadline(); String solutionsSimulatorText(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages.properties index 24f5514f74a..b8edfb0f7a4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages.properties @@ -15,6 +15,8 @@ countdownHours=Hours countdownMinutes=Mins countdownSeconds=Secs live=Live +finished=Finished +watchNow=Watch now lastUpdate=Last Update leaderBoard=LeaderBoard boxNewsUpdateMoreLink=Report news @@ -32,11 +34,21 @@ boxWeatherUnit=KTS defaultTitle=SAP Sailing Analytics eventHeaderMedia=Media eventHeaderOverview=Overview -eventHeaderRaces=Races +eventHeaderRaces=Schedule eventHeaderRegattas=Regattas -eventHeaderSchedule=Schedule +seriesHeaderOverview=About the Series +seriesHeaderUpcoming=Upcoming Events +seriesHeaderRecent=Recent Events +seriesHeaderLeaderboard=Leaderboard +seriesOverviewHeaderRecent=Latest Series Events +seriesOverviewReadMore=More +eventsOverviewRecentEvents=Events +eventsOverviewRecentCountries=Countries +eventsOverviewRecentSailors=Sailors +eventsOverviewRecentTrackedRaces=Tracked Races eventResultsHeadline=Winners and Results eventResultsBoatClassesDropDown=All Boat Classes +eventOverviewMoreEvents=More Events eventOverviewRecentEvents=Recent Events eventOverviewUpcomingDate=Date eventOverviewUpcomingEvent=Event @@ -46,7 +58,8 @@ eventOverviewUpcomingSeries=Series eventOverviewUpcomingTeaser=More Events To Be Announced Soon! eventQuickfinderTitle=Event Quick-Finder eventRegattaHeaderLeaderboard=Leaderboard -eventRegattaHeaderRaceSchedule=Race Schedule +eventRegattaHeaderRaceRaces=Races +eventRegattaListAllBoatClasses=All boat classes eventRegattaLeaderboardCompetitor=Competitor eventRegattaLeaderboardExtendLeaderboard=Extend Leaderboard eventRegattaLeaderboardFinishedMessage=No more races @@ -54,16 +67,27 @@ eventRegattaLeaderboardLastScoreUpdate=Last Score Update eventRegattaLeaderboardName=Name eventRegattaLeaderboardRegattaRank=Regatta Rank eventRegattaLeaderboardTotalPoints=Total Points +eventRegattaRaceWatch=Watch live +eventRegattaRaceAnalyse=Analyze Race +eventRegattaRaceNotTracked=Not Tracked +eventRegattaRaceFinished=Finished at: +eventRegattaRaceStarted=Started at: +eventRegattaRaceScheduled=Scheduled for: +eventRegattaRacesLegendGps=Tracking +eventRegattaRacesLegendWind=Wind Data +eventRegattaRacesLegendVideo=Video Stream +eventRegattaRacesLegendAudio=Audio Stream eventSponsorsTitle=Event Sponsorships -footerCopyright=\u00A9 2014 SAP Sailing Analytics +footerCopyright=© 2014 SAP Sailing Analytics footerLanguage=SAP Sailing offered in footerLegal=Legal Disclosure footerPrivacy=Privacy +footerFeedback=Feedback headerEvents=Events headerHome=Home headerLogo=SAP Sailing Analytics headerSearch=Search -headerSearchPlaceholder=Search SAPSailing.com +headerSearchPlaceholder=Search headerSolutions=Solutions headerSponsoring=Sponsoring latestRaceResultsHeadline=Latest Official Race Results @@ -75,7 +99,6 @@ latestRaceResultsRefresh=refresh leaderboardQuickAccessLabel=Leaderboard Quick Access mainEventShowAll=Show All Events mainEventTitle=Latest Events from the Sailing World -mainMediaShowMore=Show More mainMediaSubtitle=Get lost in the latest and most beautiful impressions from your favorite sailing event. mainMediaTitle=Sailing loves Photography mainMediaVideosSubtitle=Immerse yourself in the world of sailing and check out our latest events for more videos. @@ -83,12 +106,16 @@ mainMediaVideosTitle=Recent Video Entries mainSponsorsReadMore=Read More mediaTeaserPhotosTitle=Photos mediaTeaserVideosTitle=Videos -regattaIntroContentCompetitors=Competitors -regattaIntroContentCourse=Course -regattaIntroContentRaces=Planned Races -regattaIntroContentScoring=Scoring -regattaIntroContentMethod=Method -regattaIntroContentWindAvg=Wind Average +regattaCompetitors=Competitors +regattaRaces=Races +regattaTracked=Tracked +regattaRegattaStarts=Regatta will start +regattaPts=Pts. +regattaCourse=Course +regattaArea=Area +regattaFinishedAt=Finished at +regattaScheduledAt=Scheduled at +regattaStartedAt=Started at regattasResultsTitle=Winner and Results searchResultHeaderButton=Search searchResultHeaderLabel=Your Search @@ -100,19 +127,25 @@ searchResultSortLabel=Sort by searchResultSortNewest=Neueste searchResultSortOldest=Älteste searchResultSortRelevance=Relevance +searchResultCount=About 2,450 reslts where found for 'Schnitzel' sharingEmail=Send an email sharingFacebook=Share on Facebook sharingTwitter=Tweet about it socialFooterShare=Share this on socialFooterTitle=Recommend SAP Sailing Analytics +solutionsSAPNav=SAP Sailing Analytics solutionsSAPHeadline=SAP Sailing Analytics solutionsSAPText1=By delivering real time analytics around race rankings, speeds, maneuvers, bearings etc., SAP is helping to simplify and demystify the complex sport of sailing. solutionsSAPText2=SAP Sailing Analytics provide insights and transparency to the world of sailing by utilizing Cloud and In-Memory Technology, processing GPS and wind measurement data in real time and visualizing contents in various frontends accessible from anywhere. +solutionsRaceNav=Race Committee App solutionsRaceHeadline=Race Committee App solutionsRaceText=The SAP Race Committee App delivers greater efficiency and control to race organizers by automating and simplifying their manual tasks and communication during running sailing regattas. The Race Committee App helps simplify the operation of running and managing race events to help race committees operate smarter. +solutionsPostNav=Post-Race Analytics solutionsPostHeadline=Post-Race Analytics -solutionsPostText=Access to data collected at sailing events gives sailors the opportunity to assess and analyse their performances to help develop strategies and sail better. SAP Business Analytics solutions provide sailors, coaches, fans and media with tools to browse and analyse historical data across many regattas and races. SAP HANA allows them to learn about performance patterns, tendencies and sailor profiles in a simple, fast and efficient way in order to optimize their own performance and develop successful strategies for future regattas. +solutionsPostText=Access to data collected at sailing events gives sailors the opportunity to assess and analyse their performances to help develop strategies and sail better.
SAP Business Analytics solutions provide sailors, coaches, fans and media with tools to browse and analyse historical data across many regattas and races. SAP HANA allows them to learn about performance patterns, tendencies and sailor profiles in a simple, fast and efficient way in order to optimize their own performance and develop successful strategies for future regattas. +solutionsTrainingNav=Training Diary solutionsTrainingHeadline=SAP Sail Better \u2013 STG Training Diary solutionsTrainingText=The STG Training Diary supports the daily documentation and analysis of an athlete\u2019s physical condition and training efforts in the areas of water training, physical training, boat work, mental, theory as well as other activities like education or travel. +solutionsSimulatorNav=Strategy Simulator solutionsSimulatorHeadline=Strategy Simulator solutionsSimulatorText=Choosing the right strategy can provide great competitive advantage during a race. The Strategy Simulator simplifies determining the best sailing strategy for various wind conditions and water currents. Since wind and current can be changed in the simulation right away, the robustness of a strategy can be easily evaluated even for uncertain weather conditions. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages_de.properties index f0f4b3e86b2..c040ddcb38e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/i18n/TextMessages_de.properties @@ -15,6 +15,8 @@ countdownHours=Hours countdownMinutes=Mins countdownSeconds=Secs live=Live +finished=Finished +watchNow=Watch now lastUpdate=Last Update leaderBoard=LeaderBoard boxNewsUpdateMoreLink=Report news @@ -32,11 +34,21 @@ boxWeatherUnit=KTS defaultTitle=SAP Sailing Analytics eventHeaderMedia=Media eventHeaderOverview=Overview -eventHeaderRaces=Races +eventHeaderRaces=Schedule eventHeaderRegattas=Regattas -eventHeaderSchedule=Schedule +seriesHeaderOverview=About the Series +seriesHeaderUpcoming=Upcoming Events +seriesHeaderRecent=Recent Events +seriesHeaderLeaderboard=Leaderboard +seriesOverviewHeaderRecent=Latest Series Events +seriesOverviewReadMore=More +eventsOverviewRecentEvents=Events +eventsOverviewRecentCountries=Countries +eventsOverviewRecentSailors=Sailors +eventsOverviewRecentTrackedRaces=Tracked Races eventResultsHeadline=Winners and Results eventResultsBoatClassesDropDown=All Boat Classes +eventOverviewMoreEvents=More Events eventOverviewRecentEvents=Recent Events eventOverviewUpcomingDate=Date eventOverviewUpcomingEvent=Event @@ -46,7 +58,8 @@ eventOverviewUpcomingSeries=Series eventOverviewUpcomingTeaser=More Events To Be Announced Soon! eventQuickfinderTitle=Event Quick-Finder eventRegattaHeaderLeaderboard=Leaderboard -eventRegattaHeaderRaceSchedule=Race Schedule +eventRegattaHeaderRaceRaces=Races +eventRegattaListAllBoatClasses=All boat classes eventRegattaLeaderboardCompetitor=Competitor eventRegattaLeaderboardExtendLeaderboard=Extend Leaderboard eventRegattaLeaderboardFinishedMessage=No more races @@ -54,16 +67,27 @@ eventRegattaLeaderboardLastScoreUpdate=Last Score Update eventRegattaLeaderboardName=Name eventRegattaLeaderboardRegattaRank=Regatta Rank eventRegattaLeaderboardTotalPoints=Total Points +eventRegattaRaceWatch=Watch live +eventRegattaRaceAnalyse=Analyze Race +eventRegattaRaceNotTracked=Not Tracked +eventRegattaRaceFinished=Finished at: +eventRegattaRaceStarted=Started at: +eventRegattaRaceScheduled=Scheduled for: +eventRegattaRacesLegendGps=Tracking +eventRegattaRacesLegendWind=Wind Data +eventRegattaRacesLegendVideo=Video Stream +eventRegattaRacesLegendAudio=Audio Stream eventSponsorsTitle=Event Sponsorships -footerCopyright=\u00A9 2014 SAP Sailing Analytics +footerCopyright=© 2014 SAP Sailing Analytics footerLanguage=SAP Sailing offered in footerLegal=Legal Disclosure footerPrivacy=Privacy +footerFeedback=Feedback headerEvents=Events headerHome=Home headerLogo=SAP Sailing Analytics headerSearch=Search -headerSearchPlaceholder=Search SAPSailing.com +headerSearchPlaceholder=Search headerSolutions=Solutions headerSponsoring=Sponsoring latestRaceResultsHeadline=Latest Official Race Results @@ -75,7 +99,6 @@ latestRaceResultsRefresh=refresh leaderboardQuickAccessLabel=Leaderboard Quick Access mainEventShowAll=Show All Events mainEventTitle=Latest Events from the Sailing World -mainMediaShowMore=Show More mainMediaSubtitle=Get lost in the latest and most beautiful impressions from your favorite sailing event. mainMediaTitle=Sailing loves Photography mainMediaVideosSubtitle=Immerse yourself in the world of sailing and check out our latest events for more videos. @@ -83,12 +106,16 @@ mainMediaVideosTitle=Recent Video Entries mainSponsorsReadMore=Read More mediaTeaserPhotosTitle=Photos mediaTeaserVideosTitle=Videos -regattaIntroContentCompetitors=Competitors -regattaIntroContentCourse=Course -regattaIntroContentRaces=Planned Races -regattaIntroContentScoring=Scoring -regattaIntroContentMethod=Method -regattaIntroContentWindAvg=Wind Average +regattaCompetitors=Competitors +regattaRaces=Races +regattaTracked=Tracked +regattaRegattaStarts=Regatta will start +regattaPts=Pts. +regattaCourse=Course +regattaArea=Area +regattaFinishedAt=Finished at +regattaScheduledAt=Scheduled at +regattaStartedAt=Started at regattasResultsTitle=Winner and Results searchResultHeaderButton=Search searchResultHeaderLabel=Your Search @@ -100,19 +127,25 @@ searchResultSortLabel=Sort by searchResultSortNewest=Neueste searchResultSortOldest=Älteste searchResultSortRelevance=Relevance +searchResultCount=About 2,450 reslts where found for 'Schnitzel' sharingEmail=Send an email sharingFacebook=Share on Facebook sharingTwitter=Tweet about it socialFooterShare=Share this on socialFooterTitle=Recommend SAP Sailing Analytics +solutionsSAPNav=SAP Sailing Analytics solutionsSAPHeadline=SAP Sailing Analytics solutionsSAPText1=By delivering real time analytics around race rankings, speeds, maneuvers, bearings etc., SAP is helping to simplify and demystify the complex sport of sailing. solutionsSAPText2=SAP Sailing Analytics provide insights and transparency to the world of sailing by utilizing Cloud and In-Memory Technology, processing GPS and wind measurement data in real time and visualizing contents in various frontends accessible from anywhere. +solutionsRaceNav=Race Committee App solutionsRaceHeadline=Race Committee App solutionsRaceText=The SAP Race Committee App delivers greater efficiency and control to race organizers by automating and simplifying their manual tasks and communication during running sailing regattas. The Race Committee App helps simplify the operation of running and managing race events to help race committees operate smarter. +solutionsPostNav=Post-Race Analytics solutionsPostHeadline=Post-Race Analytics -solutionsPostText=Access to data collected at sailing events gives sailors the opportunity to assess and analyse their performances to help develop strategies and sail better. SAP Business Analytics solutions provide sailors, coaches, fans and media with tools to browse and analyse historical data across many regattas and races. SAP HANA allows them to learn about performance patterns, tendencies and sailor profiles in a simple, fast and efficient way in order to optimize their own performance and develop successful strategies for future regattas. +solutionsPostText=Access to data collected at sailing events gives sailors the opportunity to assess and analyse their performances to help develop strategies and sail better.
SAP Business Analytics solutions provide sailors, coaches, fans and media with tools to browse and analyse historical data across many regattas and races. SAP HANA allows them to learn about performance patterns, tendencies and sailor profiles in a simple, fast and efficient way in order to optimize their own performance and develop successful strategies for future regattas. +solutionsTrainingNav=Training Diary solutionsTrainingHeadline=SAP Sail Better \u2013 STG Training Diary solutionsTrainingText=The STG Training Diary supports the daily documentation and analysis of an athlete\u2019s physical condition and training efforts in the areas of water training, physical training, boat work, mental, theory as well as other activities like education or travel. +solutionsSimulatorNav=Strategy Simulator solutionsSimulatorHeadline=Strategy Simulator solutionsSimulatorText=Choosing the right strategy can provide great competitive advantage during a race. The Strategy Simulator simplifies determining the best sailing strategy for various wind conditions and water currents. Since wind and current can be changed in the simulation right away, the robustness of a strategy can be easily evaluated even for uncertain weather conditions. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventActivity.java index f9989955d8a..ede8ac05461 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventActivity.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.home.client.place.event; +import java.util.List; import java.util.UUID; import com.google.gwt.activity.shared.AbstractActivity; @@ -8,31 +9,59 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; +import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; +import com.sap.sse.gwt.client.player.Timer; +import com.sap.sse.gwt.client.player.Timer.PlayModes; public class EventActivity extends AbstractActivity { private final EventClientFactory clientFactory; private final EventPlace eventPlace; + private final Timer timerForClientServerOffset; + public EventActivity(EventPlace place, EventClientFactory clientFactory) { this.clientFactory = clientFactory; this.eventPlace = place; + + timerForClientServerOffset = new Timer(PlayModes.Replay); } @Override public void start(final AcceptsOneWidget panel, final EventBus eventBus) { + final long clientTimeWhenRequestWasSent = System.currentTimeMillis(); clientFactory.getSailingService().getEventById(UUID.fromString(eventPlace.getEventUuidAsString()), new AsyncCallback() { @Override - public void onSuccess(EventDTO event) { - final EventView view = clientFactory.createEventView(event); - panel.setWidget(view.asWidget()); + public void onSuccess(final EventDTO event) { + + clientFactory.getSailingService().getRegattaStructureForEvent(event.id, new AsyncCallback>() { + @Override + public void onSuccess(List raceGroups) { + for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) { + final long clientTimeWhenResponseWasReceived = System.currentTimeMillis(); + if (leaderboardGroupDTO.getAverageDelayToLiveInMillis() != null) { + timerForClientServerOffset.setLivePlayDelayInMillis(leaderboardGroupDTO.getAverageDelayToLiveInMillis()); + } + timerForClientServerOffset.adjustClientServerOffset(clientTimeWhenRequestWasSent, leaderboardGroupDTO.getCurrentServerTime(), clientTimeWhenResponseWasReceived); + } + + final EventView view = clientFactory.createEventView(event, raceGroups, eventPlace.getLeaderboardIdAsNameString(), timerForClientServerOffset); + panel.setWidget(view.asWidget()); + } + + @Override + public void onFailure(Throwable caught) { + Window.alert("Shit happens"); + } + }); } @Override public void onFailure(Throwable caught) { Window.alert("Shit happens"); } - }); + }); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventClientFactory.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventClientFactory.java index 57e2e5495e8..7d07e0c4625 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventClientFactory.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventClientFactory.java @@ -1,8 +1,12 @@ package com.sap.sailing.gwt.home.client.place.event; +import java.util.List; + import com.sap.sailing.gwt.ui.client.SailingClientFactory; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; +import com.sap.sse.gwt.client.player.Timer; public interface EventClientFactory extends SailingClientFactory { - EventView createEventView(EventDTO event); + EventView createEventView(EventDTO event, List raceGroups, String leaderboardName, Timer timerForClientServerOffset); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventPageNavigator.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventPageNavigator.java index 9c693af947e..f6b0104553d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventPageNavigator.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventPageNavigator.java @@ -1,5 +1,7 @@ package com.sap.sailing.gwt.home.client.place.event; +import com.sap.sailing.domain.common.dto.RaceDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; public interface EventPageNavigator { @@ -7,5 +9,7 @@ public interface EventPageNavigator { void goToRegattas(); void goToSchedule(); void goToMedia(); - void goToRegattaRaces(StrippedLeaderboardDTO leaderboard); + void goToRegattaRaces(LeaderboardGroupDTO leaderboardGroup, StrippedLeaderboardDTO leaderboard); + void openRaceViewer(StrippedLeaderboardDTO leaderboard, RaceDTO race); + void openLeaderboardViewer(LeaderboardGroupDTO leaderboardGroup, StrippedLeaderboardDTO leaderboard); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventPlace.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventPlace.java index b62b27ad7af..12070c058ca 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventPlace.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/EventPlace.java @@ -1,29 +1,39 @@ package com.sap.sailing.gwt.home.client.place.event; -import com.google.gwt.place.shared.Place; import com.google.gwt.place.shared.PlaceTokenizer; +import com.sap.sailing.gwt.home.client.AbstractBasePlace; -public class EventPlace extends Place { +public class EventPlace extends AbstractBasePlace { private final String eventUuidAsString; + private final String leaderboardIdAsNameString; public EventPlace(String eventUuidAsString) { - super(); + this(eventUuidAsString, null); + } + + public EventPlace(String eventUuidAsString, String leaderboardIdAsNameString) { + super("eventId", eventUuidAsString, "leaderboardName", leaderboardIdAsNameString); this.eventUuidAsString = eventUuidAsString; + this.leaderboardIdAsNameString = leaderboardIdAsNameString; } public String getEventUuidAsString() { return eventUuidAsString; } + public String getLeaderboardIdAsNameString() { + return leaderboardIdAsNameString; + } + public static class Tokenizer implements PlaceTokenizer { @Override public String getToken(EventPlace place) { - return place.getEventUuidAsString(); + return place.getParametersAsToken(); } @Override - public EventPlace getPlace(String eventUuidAsString) { - return new EventPlace(eventUuidAsString); + public EventPlace getPlace(String url) { + return new EventPlace(url); } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/TabletAndDesktopEventView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/TabletAndDesktopEventView.java index bb4743c75e0..8d70714f0f7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/TabletAndDesktopEventView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/TabletAndDesktopEventView.java @@ -1,13 +1,19 @@ package com.sap.sailing.gwt.home.client.place.event; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.google.gwt.core.client.GWT; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; +import com.sap.sailing.domain.common.dto.RaceDTO; import com.sap.sailing.gwt.home.client.place.event.header.EventHeader; import com.sap.sailing.gwt.home.client.place.event.media.EventMedia; import com.sap.sailing.gwt.home.client.place.event.overview.EventOverview; @@ -15,8 +21,15 @@ import com.sap.sailing.gwt.home.client.place.event.regattalist.EventRegattaList; import com.sap.sailing.gwt.home.client.place.event.regattaschedule.EventRegattaSchedule; import com.sap.sailing.gwt.home.client.place.event.schedule.EventSchedule; import com.sap.sailing.gwt.home.client.shared.eventsponsors.EventSponsors; +import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory; +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sailing.gwt.ui.raceboard.RaceBoardViewConfiguration; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; +import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; +import com.sap.sailing.gwt.ui.shared.RegattaDTO; import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; +import com.sap.sse.gwt.client.player.Timer; public class TabletAndDesktopEventView extends Composite implements EventView, EventPageNavigator { private static EventViewUiBinder uiBinder = GWT.create(EventViewUiBinder.class); @@ -35,10 +48,14 @@ public class TabletAndDesktopEventView extends Composite implements EventView, E private final List pageElements; - public TabletAndDesktopEventView(EventDTO event) { + private final SailingServiceAsync sailingService; + + public TabletAndDesktopEventView(SailingServiceAsync sailingService, EventDTO event, List raceGroups, String leaderboardName, + Timer timerForClientServerOffset) { + this.sailingService = sailingService; eventHeader = new EventHeader(event, this); eventRegattaList = new EventRegattaList(event, this); - eventRegattaSchedule = new EventRegattaSchedule(event, this); + eventRegattaSchedule = new EventRegattaSchedule(event, timerForClientServerOffset, this); eventOverview = new EventOverview(event); eventSchedule = new EventSchedule(event); eventMedia = new EventMedia(event); @@ -46,36 +63,156 @@ public class TabletAndDesktopEventView extends Composite implements EventView, E initWidget(uiBinder.createAndBindUi(this)); pageElements = Arrays.asList(new Widget[] { eventOverview, eventRegattaList, eventRegattaSchedule, eventMedia, eventSchedule }); - setVisibleEventElement(eventOverview); + - eventSponsors.setEventSponsors(event); + int leaderboardsCount = 0; + int leaderboardsGroupCount = event.getLeaderboardGroups().size(); + for(LeaderboardGroupDTO leaderboardGroup: event.getLeaderboardGroups()) { + leaderboardsCount += leaderboardGroup.getLeaderboards().size(); + } + + if(leaderboardsGroupCount == 0 || leaderboardsCount == 0) { + Window.alert("There is no data available for this event."); + } else { + + LeaderboardGroupDTO selectedLeaderboardGroup = null; + StrippedLeaderboardDTO selectedLeaderboard = null; + + // find the preselected leaderboard (if one exist) + if (leaderboardName != null) { + for (LeaderboardGroupDTO leaderboardGroup : event.getLeaderboardGroups()) { + for (StrippedLeaderboardDTO leaderboard : leaderboardGroup.getLeaderboards()) { + if (leaderboard.name.equals(leaderboardName)) { + selectedLeaderboardGroup = leaderboardGroup; + selectedLeaderboard = leaderboard; + break; + } + } + } + } + + // in case we only have one regatta/leaderboard we go directly to the 'races' page + if(selectedLeaderboard == null && leaderboardsCount == 1) { + for (LeaderboardGroupDTO leaderboardGroup : event.getLeaderboardGroups()) { + if(leaderboardGroup.getLeaderboards().size() > 0) { + selectedLeaderboard = leaderboardGroup.getLeaderboards().get(0); + selectedLeaderboardGroup = leaderboardGroup; + } + } + } + + if(selectedLeaderboard != null && selectedLeaderboardGroup != null) { + goToRegattaRaces(selectedLeaderboardGroup, selectedLeaderboard); + } else { + goToRegattas(); + } + if(event.getSponsorImageURLs() != null && event.getSponsorImageURLs().size() > 0) { + eventSponsors.setVisible(false); + eventSponsors.setEventSponsors(event.getSponsorImageURLs()); + } else { + eventSponsors.setVisible(false); + eventSponsors.setEventSponsors(null); + } + + } } @Override public void goToOverview() { setVisibleEventElement(eventOverview); + eventHeader.setDataNavigationType("normal"); } @Override public void goToRegattas() { setVisibleEventElement(eventRegattaList); + eventHeader.setDataNavigationType("normal"); } @Override - public void goToRegattaRaces(StrippedLeaderboardDTO leaderboard) { - setVisibleEventElement(eventRegattaSchedule); + public void goToRegattaRaces(final LeaderboardGroupDTO leaderboardGroup, final StrippedLeaderboardDTO leaderboard) { + switch (leaderboard.type) { + case RegattaLeaderboard: + sailingService.getRegattaByName(leaderboard.regattaName, new AsyncCallback() { + @Override + public void onSuccess(RegattaDTO regatta) { + eventRegattaSchedule.setRacesFromRegatta(regatta, leaderboardGroup, leaderboard); + eventHeader.setDataNavigationType("compact"); + setVisibleEventElement(eventRegattaSchedule); + } + + @Override + public void onFailure(Throwable caught) { + Window.alert("Shit happens"); + } + }); + break; + case FlexibleLeaderboard: + eventRegattaSchedule.setRacesFromFlexibleLeaderboard(leaderboardGroup, leaderboard); + eventHeader.setDataNavigationType("compact"); + setVisibleEventElement(eventRegattaSchedule); + break; + case FlexibleMetaLeaderboard: + eventHeader.setDataNavigationType("compact"); + setVisibleEventElement(eventRegattaSchedule); + break; + case RegattaMetaLeaderboard: + eventHeader.setDataNavigationType("compact"); + setVisibleEventElement(eventRegattaSchedule); + break; + } } @Override public void goToSchedule() { setVisibleEventElement(eventSchedule); + eventHeader.setDataNavigationType("normal"); } @Override public void goToMedia() { setVisibleEventElement(eventMedia); + eventHeader.setDataNavigationType("normal"); + } + + @Override + public void openRaceViewer(StrippedLeaderboardDTO leaderboard, RaceDTO race) { + RegattaAndRaceIdentifier raceIdentifier = race.getRaceIdentifier(); + String link = EntryPointLinkFactory.createRaceBoardLink(createRaceBoardLinkParameters(leaderboard.name, raceIdentifier)); + Window.open(link, "_blank", ""); } + @Override + public void openLeaderboardViewer(LeaderboardGroupDTO leaderboardGroup, StrippedLeaderboardDTO leaderboard) { + String link = EntryPointLinkFactory.createLeaderboardLink(createLeaderboardLinkParameters(leaderboardGroup, leaderboard)); + Window.open(link, "_blank", ""); + } + + private Map createRaceBoardLinkParameters(String leaderboardName, RegattaAndRaceIdentifier raceIdentifier) { + Map linkParams = new HashMap(); + linkParams.put("leaderboardName", leaderboardName); + linkParams.put("raceName", raceIdentifier.getRaceName()); + linkParams.put(RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, "true"); + linkParams.put(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_MAPCONTROLS, "true"); + linkParams.put(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_NAVIGATION_PANEL, "true"); + linkParams.put("regattaName", raceIdentifier.getRegattaName()); + return linkParams; + } + + private Map createLeaderboardLinkParameters(LeaderboardGroupDTO leaderboardGroup, StrippedLeaderboardDTO leaderboard) { + Map linkParams = new HashMap(); + linkParams.put("name", leaderboard.name); + linkParams.put("showRaceDetails", "true"); + linkParams.put("embedded", "true"); + if (leaderboard.displayName != null) { + linkParams.put("displayName", leaderboard.displayName); + } + if(leaderboardGroup != null) { + linkParams.put("leaderboardGroupName", leaderboardGroup.getName()); + } + return linkParams; + } + private void setVisibleEventElement(Widget visibleWidget) { for (Widget element : pageElements) { element.setVisible(element == visibleWidget); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.css index 00b88d3281d..d39b7c45b44 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.css @@ -1,6 +1,73 @@ /** * The header of the pages to an event */ +.dropdown { + font-size: 16px; + font-size: 1rem; + width: 18.75em; + max-width: 100%; + display: inline-block; + text-align: left; +} +.dropdown_head { + cursor: pointer; + display: block; +} +.dropdown_head_title { + cursor: pointer; + background: #f8f8f8; + color: #666; + height: 2.5625em; + line-height: 2.5em; + padding-left: 0.9375em; + font-weight: 700; +} +.dropdown_head_titlebutton { + float: right; +} +.dropdown_content { + position: absolute; + z-index: 1; + background: #f6f9fc; + display: none; + width: 18.75em; + height: auto; + max-height: 21.875em; + overflow: auto; + -webkit-box-shadow: 0 0.0625em 0.25em #ccc; + box-shadow: 0 0.0625em 0.25em #ccc; + border-bottom: solid 1px #ccc; +} +.dropdown_content_link { + display: block; + cursor: pointer; + padding: 1.25em 0.9375em; + border-bottom: 1px solid #ddd; +} +.dropdown_content_link:hover, +.dropdown_content_link:focus { + background: #f8f8f8; + text-decoration: none; +} +.dropdown_content_link:hover .dropdown_content_link_title, +.dropdown_content_link:focus .dropdown_content_link_title { + text-decoration: underline; +} +.dropdown_content_link_title { + color: #008fcc; + display: block; + font-weight: 700; + font-size: 1.125em; +} +.dropdown_content_link_subtitle { + color: #666; + font-size: 1em; +} +.leaderboardquickaccess { + font-size: 16px; + font-size: 1rem; + text-align: right; +} .eventheaderwrapper { font-size: 16px; font-size: 1rem; @@ -23,7 +90,7 @@ font-size: 16px; font-size: 1rem; background: #f2f2f2; - padding: 1.875em; + padding: 1.875em 0; } .eventheader_intro { padding-left: 9.6875em; @@ -56,7 +123,8 @@ .eventheader_intro_details_item { display: inline-block; border-right: 1px solid #ddd; - padding: 0.25em 0.625em; + padding: 0.25em 0.625em 0.25em 0; + margin-right: 0.625em; } .eventheader_intro_details_itemlink { color: inherit; @@ -64,9 +132,14 @@ .eventheader_intro_details_item:first-child { padding-left: 0; } +.eventheader_intro_details_item:nth-child\(2\) { + border: none; +} .eventheader_intro_details_item:last-child { - border-right: none; - padding-right: 0; + display: block; + padding: 0; + border: none; + margin: 0; } .eventheader_sharing { text-align: right; @@ -134,7 +207,7 @@ } .eventnavigationcompactfloating { position: fixed; - top: -10em; + top: -5em; left: 0; right: 0; z-index: 5; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.java index f3d096a0e8a..8039adc309a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.java @@ -1,8 +1,5 @@ package com.sap.sailing.gwt.home.client.place.event.header; -import java.util.Arrays; -import java.util.List; - import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.ImageElement; @@ -11,7 +8,6 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; -import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; @@ -27,24 +23,25 @@ public class EventHeader extends Composite { private final EventDTO event; - @UiField Anchor overviewLink; - @UiField Anchor regattasLink; - @UiField Anchor scheduleLink; - @UiField Anchor mediaLink; - - @UiField Anchor overviewLink2; - @UiField Anchor regattasLink2; - @UiField Anchor scheduleLink2; - @UiField Anchor mediaLink2; - - @UiField Anchor overviewLink3; - @UiField Anchor regattasLink3; - @UiField Anchor scheduleLink3; - @UiField Anchor mediaLink3; +// @UiField Anchor overviewLink; + @UiField Anchor regattasLink; +// @UiField Anchor scheduleLink; +// @UiField Anchor mediaLink; +// +// @UiField Anchor overviewLink2; + @UiField Anchor regattasLink2; +// @UiField Anchor scheduleLink2; +// @UiField Anchor mediaLink2; +// +// @UiField Anchor overviewLink3; +// @UiField Anchor regattasLink3; +// @UiField Anchor scheduleLink3; +// @UiField Anchor mediaLink3; + @UiField DivElement eventHeaderWrapperDiv; @UiField SpanElement eventName; @UiField SpanElement eventName2; - @UiField SpanElement eventName3; +// @UiField SpanElement eventName3; @UiField SpanElement eventDate; @UiField SpanElement eventDescription; @UiField SpanElement venueName; @@ -52,18 +49,13 @@ public class EventHeader extends Composite { @UiField ImageElement eventLogo; @UiField ImageElement eventLogo2; - @UiField ImageElement eventLogo3; - - @UiField DivElement eventHeaderDiv; - @UiField DivElement eventNavigationNormalDiv; - @UiField DivElement eventNavigationCompactDiv; - @UiField DivElement eventNavigationFloatingDiv; +// @UiField ImageElement eventLogo3; private final String defaultLogoUrl = "http://static.sapsailing.com/newhome/default_event_logo.png"; - private final List links1; - private final List links2; - private final List links3; +// private final List links1; +// private final List links2; +// private final List links3; private final EventPageNavigator pageNavigator; @@ -74,20 +66,25 @@ public class EventHeader extends Composite { EventHeaderResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); - links1 = Arrays.asList(new Anchor[] { overviewLink, regattasLink, scheduleLink, mediaLink }); - links2 = Arrays.asList(new Anchor[] { overviewLink2, regattasLink2, scheduleLink2, mediaLink2 }); - links3 = Arrays.asList(new Anchor[] { overviewLink3, regattasLink3, scheduleLink3, mediaLink3 }); - setActiveLink(links1, overviewLink); - setActiveLink(links2, overviewLink2); - setActiveLink(links3, overviewLink3); +// links1 = Arrays.asList(new Anchor[] { overviewLink, regattasLink, scheduleLink, mediaLink }); +// links2 = Arrays.asList(new Anchor[] { overviewLink2, regattasLink2, scheduleLink2, mediaLink2 }); +// links3 = Arrays.asList(new Anchor[] { overviewLink3, regattasLink3, scheduleLink3, mediaLink3 }); +// setActiveLink(links1, overviewLink); +// setActiveLink(links2, overviewLink2); +// setActiveLink(links3, overviewLink3); + setDataNavigationType("normal"); updateUI(); } + public void setDataNavigationType(String dataNavigationType) { + eventHeaderWrapperDiv.setAttribute("data-navigationtype", dataNavigationType); + } + private void updateUI() { eventName.setInnerHTML(event.getName()); - eventName2.setInnerHTML(event.getName()+"2"); - eventName3.setInnerHTML(event.getName()+"3"); + eventName2.setInnerHTML(event.getName()); +// eventName3.setInnerHTML(event.getName()); venueName.setInnerHTML(event.venue.getName()); eventDate.setInnerHTML(EventDatesFormatterUtil.formatDateRangeWithYear(event.startDate, event.endDate)); @@ -101,30 +98,30 @@ public class EventHeader extends Composite { String logoUrl = event.getLogoImageURL() != null ? event.getLogoImageURL() : defaultLogoUrl; eventLogo.setSrc(logoUrl); eventLogo2.setSrc(logoUrl); - eventLogo3.setSrc(logoUrl); +// eventLogo3.setSrc(logoUrl); } - @UiHandler("overviewLink") - void overviewClicked(ClickEvent event) { - showOverview(); - } +// @UiHandler("overviewLink") +// void overviewClicked(ClickEvent event) { +// showOverview(); +// } +// +// @UiHandler("overviewLink2") +// void overview2Clicked(ClickEvent event) { +// showOverview(); +// } +// +// @UiHandler("overviewLink3") +// void overview3Clicked(ClickEvent event) { +// showOverview(); +// } - @UiHandler("overviewLink2") - void overview2Clicked(ClickEvent event) { - showOverview(); - } - - @UiHandler("overviewLink3") - void overview3Clicked(ClickEvent event) { - showOverview(); - } - - private void showOverview() { - pageNavigator.goToOverview(); - setActiveLink(links1, overviewLink); - setActiveLink(links2, overviewLink2); - setActiveLink(links3, overviewLink3); - } +// private void showOverview() { +// pageNavigator.goToOverview(); +// setActiveLink(links1, overviewLink); +// setActiveLink(links2, overviewLink2); +// setActiveLink(links3, overviewLink3); +// } @UiHandler("regattasLink") void regattasClicked(ClickEvent event) { @@ -136,61 +133,61 @@ public class EventHeader extends Composite { showRegattas(); } - @UiHandler("regattasLink3") - void regattas3Clicked(ClickEvent event) { - showRegattas(); - } - +// @UiHandler("regattasLink3") +// void regattas3Clicked(ClickEvent event) { +// showRegattas(); +// } +// private void showRegattas() { pageNavigator.goToRegattas(); - setActiveLink(links1, regattasLink); - setActiveLink(links2, regattasLink2); - setActiveLink(links3, regattasLink3); +// setActiveLink(links1, regattasLink); +// setActiveLink(links2, regattasLink2); +// setActiveLink(links3, regattasLink3); } - @UiHandler("scheduleLink") - void scheduleClicked(ClickEvent event) { - showSchedule(); - } - - @UiHandler("scheduleLink2") - void schedule2Clicked(ClickEvent event) { - showSchedule(); - } - - @UiHandler("scheduleLink3") - void schedule3Clicked(ClickEvent event) { - showSchedule(); - } - - private void showSchedule() { - pageNavigator.goToSchedule(); - setActiveLink(links1, scheduleLink); - setActiveLink(links2, scheduleLink2); - setActiveLink(links3, scheduleLink3); - } - - @UiHandler("mediaLink") - void mediaClicked(ClickEvent event) { - showMedia(); - } - - @UiHandler("mediaLink2") - void media2Clicked(ClickEvent event) { - showMedia(); - } - - @UiHandler("mediaLink3") - void media3Clicked(ClickEvent event) { - showMedia(); - } - - private void showMedia() { - pageNavigator.goToMedia(); - setActiveLink(links1, mediaLink); - setActiveLink(links2, mediaLink2); - setActiveLink(links3, mediaLink3); - } +// @UiHandler("scheduleLink") +// void scheduleClicked(ClickEvent event) { +// showSchedule(); +// } +// +// @UiHandler("scheduleLink2") +// void schedule2Clicked(ClickEvent event) { +// showSchedule(); +// } +// +// @UiHandler("scheduleLink3") +// void schedule3Clicked(ClickEvent event) { +// showSchedule(); +// } +// +// private void showSchedule() { +// pageNavigator.goToSchedule(); +// setActiveLink(links1, scheduleLink); +// setActiveLink(links2, scheduleLink2); +// setActiveLink(links3, scheduleLink3); +// } +// +// @UiHandler("mediaLink") +// void mediaClicked(ClickEvent event) { +// showMedia(); +// } +// +// @UiHandler("mediaLink2") +// void media2Clicked(ClickEvent event) { +// showMedia(); +// } +// +// @UiHandler("mediaLink3") +// void media3Clicked(ClickEvent event) { +// showMedia(); +// } +// +// private void showMedia() { +// pageNavigator.goToMedia(); +// setActiveLink(links1, mediaLink); +// setActiveLink(links2, mediaLink2); +// setActiveLink(links3, mediaLink3); +// } @Override protected void onLoad() { @@ -200,29 +197,29 @@ public class EventHeader extends Composite { } private void initNormalNavigation() { - Window.addWindowScrollHandler(new Window.ScrollHandler() { - public void onWindowScroll(Window.ScrollEvent event) { - int scrollY = Math.max(0, Window.getScrollTop()); - int navNormalOffset = eventNavigationNormalDiv.getOffsetTop(); - - if (scrollY > navNormalOffset) { - eventNavigationFloatingDiv.addClassName(EventHeaderResources.INSTANCE.css().eventnavigationfixed()); - } else { - eventNavigationFloatingDiv.removeClassName(EventHeaderResources.INSTANCE.css() - .eventnavigationfixed()); - } - } - }); +// Window.addWindowScrollHandler(new Window.ScrollHandler() { +// public void onWindowScroll(Window.ScrollEvent event) { +// int scrollY = Math.max(0, Window.getScrollTop()); +// int navNormalOffset = eventNavigationNormalDiv.getOffsetTop(); +// +// if (scrollY > navNormalOffset) { +// eventNavigationFloatingDiv.addClassName(EventHeaderResources.INSTANCE.css().eventnavigationfixed()); +// } else { +// eventNavigationFloatingDiv.removeClassName(EventHeaderResources.INSTANCE.css() +// .eventnavigationfixed()); +// } +// } +// }); } - private void setActiveLink(List linksToSet, Anchor link) { - final String activeStyle = EventHeaderResources.INSTANCE.css().eventnavigation_linkactive(); - for (Anchor l : linksToSet) { - if (l == link) { - l.addStyleName(activeStyle); - } else { - l.removeStyleName(activeStyle); - } - } - } +// private void setActiveLink(List linksToSet, Anchor link) { +// final String activeStyle = EventHeaderResources.INSTANCE.css().eventnavigation_linkactive(); +// for (Anchor l : linksToSet) { +// if (l == link) { +// l.addStyleName(activeStyle); +// } else { +// l.removeStyleName(activeStyle); +// } +// } +// } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.ui.xml index 455b28c1f39..a3f9dab8703 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeader.ui.xml @@ -7,14 +7,14 @@ - -
-
+ +
+
-
+

-
Live
+
@@ -23,74 +23,29 @@
-
-
- - - -
+
+
-
+
-
- - - - - +
+ + + +
-
+ -
-
-
-
-
-
- - - - - - - - - - -
+
{#if navigation.isEvent}{event.name}{/if navigation.isEvent}{#if navigation.isSeries}{event.name} +
+ -->
- + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeaderResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeaderResources.java index 70bc294433e..26b03780885 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeaderResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/header/EventHeaderResources.java @@ -11,6 +11,15 @@ public interface EventHeaderResources extends ClientBundle { LocalCss css(); public interface LocalCss extends CssResource { + String dropdown(); + String dropdown_head(); + String dropdown_head_title(); + String dropdown_head_titlebutton(); + String dropdown_content(); + String dropdown_content_link(); + String dropdown_content_link_title(); + String dropdown_content_link_subtitle(); + String leaderboardquickaccess(); String eventheaderwrapper(); String eventheader(); String eventnavigationnormal(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverview.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverview.css index 663f606747e..c2ac3b6301c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverview.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverview.css @@ -74,97 +74,6 @@ .columns .latestraceresults_detail_wrapperimage { max-width: none; } -.lightbox { - font-size: 16px; - font-size: 1rem; -} -.lightbox_overlay { - font-size: 16px; - font-size: 1rem; - background: #000; - opacity: 0.7; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; - filter: literal("alpha(opacity=70)"); - width: 100%; - height: 100%; - position: fixed; - left: 0; - top: 0; - z-index: 2000; - -webkit-transition: opacity 0.3s ease; - -moz-transition: opacity 0.3s ease; - -o-transition: opacity 0.3s ease; - -ms-transition: opacity 0.3s ease; - transition: opacity 0.3s ease; -} -.lightbox_overlayhidden { - opacity: 0; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; - filter: alpha(opacity=0); -} -.lightbox_content { - position: fixed; - width: 100%; - height: 100%; - opacity: 1; - -ms-filter: none; - filter: none; - top: 0; - left: 0; - z-index: 2001; - background-repeat: no-repeat; - background-position: center center; - -webkit-transition: opacity 0.3s ease; - -moz-transition: opacity 0.3s ease; - -o-transition: opacity 0.3s ease; - -ms-transition: opacity 0.3s ease; - transition: opacity 0.3s ease; -} -.lightbox_contenthidden { - opacity: 0; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; - filter: alpha(opacity=0); -} -.lightbox_content_enlargedimage { - -webkit-transition: margin 0.7s linear; - -moz-transition: margin 0.7s linear; - -o-transition: margin 0.7s linear; - -ms-transition: margin 0.7s linear; - transition: margin 0.7s linear; - display: inline-block; - position: absolute; - left: 50%; - top: 50%; -} -.lightbox_content_enlargedimage_caption { - text-align: center; - color: #f6f9fc; - font-weight: 700; -} -.lightbox_content_enlargedimage_close { - display: inline-block; - background-image: url("../images/x_lightbox.png"); - background-repeat: no-repeat; - background-position: center center; - width: 1.25em; - height: 0; - overflow: hidden; - padding-top: 1.25em; - position: absolute; - top: 1.25em; - right: 1.25em; - cursor: pointer; - z-index: 2003; -} -.lightbox_content .media_slideshow_controls { - z-index: 2002; -} -.lightbox_data { - display: none; -} -.lightbox_photo { - cursor: pointer; -} .mediateaser { font-size: 16px; font-size: 1rem; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewResources.java index aac78042d84..2dffd7be71e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/overview/EventOverviewResources.java @@ -29,17 +29,6 @@ public interface EventOverviewResources extends ClientBundle { String latestraceresults_detail_datetime(); String columns(); String latestraceresults_detail_wrapperimage(); - String lightbox(); - String lightbox_overlay(); - String lightbox_overlayhidden(); - String lightbox_content(); - String lightbox_contenthidden(); - String lightbox_content_enlargedimage(); - String lightbox_content_enlargedimage_caption(); - String lightbox_content_enlargedimage_close(); - String media_slideshow_controls(); - String lightbox_data(); - String lightbox_photo(); String mediateaser(); String mediateaser_title(); String mediateaser_title_link(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.css index 54276168f56..8197a9e24f2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.css @@ -52,15 +52,12 @@ .regattalink:hover .regatta_intro_image { opacity: 0.9; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)"; - filter: alpha(opacity=90); + filter: literal("alpha(opacity=90)"); } -.regattalink:hover .regatta_intro_header_name { - text-decoration: underline; -} -.regattalink:nth-child(even) { +.regattalink:nth-child\(even\) { background-color: #f8f8f8; } -.regattalink:nth-child(even):hover { +.regattalink:nth-child\(even\):hover { background-color: #f3f3f3; } .regatta_intro { @@ -81,8 +78,9 @@ } .regatta_intro_header { margin-bottom: 0.625em; + padding-top: 0.3125em; padding-bottom: 0.625em; - border-bottom: 1px solid #f2f2f2; + border-bottom: 1px solid #d9d9d9; position: relative; } .regatta_intro_header_logo { @@ -90,11 +88,12 @@ } .regatta_intro_header_name { display: inline-block; - font-size: 1.125em; + font-size: 1.25em; margin: 0; - margin-left: 0.25em; - padding-left: 0.5em; - border-left: 1px solid #f2f2f2; + margin-right: 0.25em; +} +.regatta_intro_header_name:hover { + text-decoration: underline; } .regatta_intro_header_labels { display: inline-block; @@ -106,11 +105,12 @@ vertical-align: baseline; } .regatta_intro_races { - min-height: 3.75em; + position: relative; + min-height: 1.875em; margin-bottom: 0.625em; padding-bottom: 0.625em; padding-left: 0.3125em; - border-bottom: 1px solid #f2f2f2; + border-bottom: 1px solid #d9d9d9; } .regatta_intro_races_race { display: inline-block; @@ -127,11 +127,24 @@ .regatta_intro_races_race[data-finished='data-finished'] { background-color: #f0ab00; } +.regatta_intro_meta { + position: relative; + font-weight: 600; +} +.regatta_intro_meta_scoring { + color: #008fcc; + display: inline-block; +} +.regatta_intro_meta_leaderboardlink { + position: absolute; + top: 0; + right: 0; + text-transform: uppercase; + line-height: 2.8125em; +} .regatta_intro_details { - font-size: 0.875em; font-weight: 600; color: #666; - text-transform: uppercase; } .regatta_intro_details_item { display: inline-block; @@ -143,10 +156,6 @@ .regatta_intro_details_item_sub { display: inline; } -.regatta_intro_details_item_sub:after { - content: ' | '; - display: inline; -} .regatta_intro_details_item_sub:last-child:after { content: ''; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.java index 0b0dc47d03e..7bd6c56e95a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.java @@ -1,10 +1,21 @@ package com.sap.sailing.gwt.home.client.place.event.regattaheader; import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.dom.client.Style.Visibility; +import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.home.client.place.event.EventPageNavigator; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; +import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; +import com.sap.sse.gwt.client.player.Timer; public class EventRegattaHeader extends Composite { private static EventRegattaHeaderUiBinder uiBinder = GWT.create(EventRegattaHeaderUiBinder.class); @@ -14,12 +25,49 @@ public class EventRegattaHeader extends Composite { @SuppressWarnings("unused") private final EventDTO event; - - public EventRegattaHeader(EventDTO event) { + private final Timer timerForClientServerOffset; + private final EventPageNavigator pageNavigator; + private StrippedLeaderboardDTO leaderboard; + + @UiField SpanElement regattaName; + @UiField SpanElement leaderboardGroupName; + @UiField SpanElement regattaPhase; + @UiField SpanElement competitorsCount; + @UiField DivElement isLiveDiv; + @UiField Anchor leaderboardLink; + + public EventRegattaHeader(EventDTO event, Timer timerForClientServerOffset, EventPageNavigator pageNavigator) { this.event = event; + this.timerForClientServerOffset = timerForClientServerOffset; + this.pageNavigator = pageNavigator; EventRegattaHeaderResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); } + + public void setData(LeaderboardGroupDTO leaderboardGroup, StrippedLeaderboardDTO leaderboard) { + this.leaderboard = leaderboard; + + boolean hasLiveRace = leaderboard.hasLiveRace(timerForClientServerOffset.getLiveTimePointInMillis()); + isLiveDiv.setAttribute("data-labeltype", hasLiveRace ? "live" : ""); + + regattaName.setInnerText(leaderboard.displayName != null ? leaderboard.displayName : leaderboard.name); + leaderboardGroupName.setInnerText(leaderboardGroup.getName()); + + if(leaderboard.rows != null) { + competitorsCount.setInnerText(String.valueOf(leaderboard.rows.size())); + } else { + competitorsCount.getStyle().setVisibility(Visibility.HIDDEN); + } + regattaPhase.setInnerText(calculateCurrentRegattaPhase(leaderboard)); + } + private String calculateCurrentRegattaPhase(StrippedLeaderboardDTO leaderboard) { + return ""; + } + + @UiHandler("leaderboardLink") + public void goToLeaderboard(ClickEvent e) { + pageNavigator.openLeaderboardViewer(null, leaderboard); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.ui.xml index 6b5129270d7..e4c3faa82ad 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeader.ui.xml @@ -8,43 +8,47 @@ - - diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeaderResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeaderResources.java index b07b8466fc5..517a4563c55 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeaderResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaheader/EventRegattaHeaderResources.java @@ -20,14 +20,17 @@ public interface EventRegattaHeaderResources extends ClientBundle { String regatta_intro_details_itemhideoncompact(); String regattalink(); String regatta_intro_image(); - String regatta_intro_header_name(); String regatta_intro(); String regatta_intro_header(); String regatta_intro_header_logo(); + String regatta_intro_header_name(); String regatta_intro_header_labels(); String label(); String regatta_intro_races(); String regatta_intro_races_race(); + String regatta_intro_meta(); + String regatta_intro_meta_scoring(); + String regatta_intro_meta_leaderboardlink(); String regatta_intro_details(); String regatta_intro_details_item(); String regatta_intro_details_item_sub(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaList.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaList.ui.xml index 46e589e0cbb..d99e54e4381 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaList.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaList.ui.xml @@ -7,8 +7,7 @@
- - +
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaListItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaListItem.java index aca55159fc0..70b1a18a39b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaListItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaListItem.java @@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.client.place.event.regattalist; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.dom.client.Style.Visibility; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; @@ -23,22 +24,16 @@ public class EventRegattaListItem extends Composite { @UiField SpanElement regattaName; @UiField SpanElement leaderboardGroupName; - @UiField SpanElement competitorsCount; - @UiField SpanElement boatDesign; - @UiField SpanElement scoringSystem; - @UiField SpanElement averageWind; - @UiField SpanElement plannedRacesCount; - @UiField SpanElement regattaSeriesName; - + @UiField SpanElement regattaPhase; @UiField DivElement isLiveElement; @UiField Anchor regattaRacesLink; @SuppressWarnings("unused") private RegattaDTO regatta; - private final LeaderboardGroupDTO leaderboardGroup; private final StrippedLeaderboardDTO leaderboard; + private final LeaderboardGroupDTO leaderboardGroup; private final EventPageNavigator pageNavigator; public EventRegattaListItem(EventPageNavigator pageNavigator, LeaderboardGroupDTO leaderboardGroup, StrippedLeaderboardDTO leaderboard) { @@ -49,23 +44,24 @@ public class EventRegattaListItem extends Composite { EventRegattaListResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); - updateUI(); + regattaName.setInnerText(leaderboard.displayName != null ? leaderboard.displayName : leaderboard.name); + leaderboardGroupName.setInnerText(leaderboardGroup.getName()); + + if(leaderboard.rows != null) { + competitorsCount.setInnerText(String.valueOf(leaderboard.rows.size())); + } else { + competitorsCount.getStyle().setVisibility(Visibility.HIDDEN); + } } @UiHandler("regattaRacesLink") public void goToRegattaRaces(ClickEvent e) { - pageNavigator.goToRegattaRaces(leaderboard); + pageNavigator.goToRegattaRaces(leaderboardGroup, leaderboard); + } + + @UiHandler("leaderboardLink") + public void goToLeaderboard(ClickEvent e) { + pageNavigator.openLeaderboardViewer(leaderboardGroup, leaderboard); } - private void updateUI() { - regattaName.setInnerText(leaderboard.displayName != null ? leaderboard.displayName : leaderboard.name); - leaderboardGroupName.setInnerText(leaderboardGroup.getName()); - - competitorsCount.setInnerText("XYZ"); - boatDesign.setInnerText("XYZ"); - scoringSystem.setInnerText("XYZ"); - averageWind.setInnerText("XYZ"); - plannedRacesCount.setInnerText("XYZ"); - regattaSeriesName.setInnerText("ABC"); - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaListItem.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaListItem.ui.xml index 25c0d87d518..bd4bfc84330 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaListItem.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattalist/EventRegattaListItem.ui.xml @@ -20,28 +20,18 @@
Phase -
+
+
+
+ Leaderboard
-
-
 
-
-
-
 
-
-
-
 
-
-
-
 
-
-
-
 
+
 
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaSchedule.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaSchedule.java index 4d2a2a451bd..52a1d3c7003 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaSchedule.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaSchedule.java @@ -2,10 +2,18 @@ package com.sap.sailing.gwt.home.client.place.event.regattaschedule; import com.google.gwt.core.client.GWT; import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.home.client.place.event.EventPageNavigator; +import com.sap.sailing.gwt.home.client.place.event.regattaheader.EventRegattaHeader; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; +import com.sap.sailing.gwt.ui.shared.RegattaDTO; +import com.sap.sailing.gwt.ui.shared.SeriesDTO; +import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; +import com.sap.sse.gwt.client.player.Timer; public class EventRegattaSchedule extends Composite { private static EventRegattaScheduleUiBinder uiBinder = GWT.create(EventRegattaScheduleUiBinder.class); @@ -13,14 +21,40 @@ public class EventRegattaSchedule extends Composite { interface EventRegattaScheduleUiBinder extends UiBinder { } + @UiField(provided=true) EventRegattaHeader regattaHeader; + @UiField HTMLPanel seriesListPanel; + @SuppressWarnings("unused") private final EventDTO event; - public EventRegattaSchedule(EventDTO event, EventPageNavigator pageNavigator) { + private final Timer timerForClientServerOffset; + private final EventPageNavigator pageNavigator; + + public EventRegattaSchedule(EventDTO event, Timer timerForClientServerOffset, EventPageNavigator pageNavigator) { this.event = event; + this.timerForClientServerOffset = timerForClientServerOffset; + this.pageNavigator = pageNavigator; + + regattaHeader = new EventRegattaHeader(event, timerForClientServerOffset, pageNavigator); EventRegattaScheduleResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); } + public void setRacesFromRegatta(RegattaDTO regatta, LeaderboardGroupDTO leaderboardGroup, StrippedLeaderboardDTO regattaLeaderboard) { + regattaHeader.setData(leaderboardGroup, regattaLeaderboard); + + for(SeriesDTO series: regatta.series) { + EventRegattaScheduleSeries eventRegattaScheduleSeries = new EventRegattaScheduleSeries(regattaLeaderboard, series, timerForClientServerOffset, pageNavigator); + seriesListPanel.add(eventRegattaScheduleSeries); + } + } + + public void setRacesFromFlexibleLeaderboard(LeaderboardGroupDTO leaderboardGroup, StrippedLeaderboardDTO flexibleLeaderboard) { + regattaHeader.setData(leaderboardGroup, flexibleLeaderboard); + + EventRegattaScheduleFleet eventRegattaScheduleFleet = new EventRegattaScheduleFleet(flexibleLeaderboard, timerForClientServerOffset, pageNavigator); + seriesListPanel.add(eventRegattaScheduleFleet); + } + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaSchedule.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaSchedule.ui.xml index 30ad210e8ad..6f8b49ec780 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaSchedule.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaSchedule.ui.xml @@ -1,30 +1,19 @@ + xmlns:s="urn:import:com.sap.sailing.gwt.home.client.place.event"> - - -

Races of regatta xyz

-
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleFleet.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleFleet.java new file mode 100644 index 00000000000..dace5004dc4 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleFleet.java @@ -0,0 +1,85 @@ +package com.sap.sailing.gwt.home.client.place.event.regattaschedule; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTMLPanel; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.domain.common.LeaderboardNameConstants; +import com.sap.sailing.domain.common.dto.FleetDTO; +import com.sap.sailing.domain.common.dto.RaceColumnDTO; +import com.sap.sailing.gwt.home.client.place.event.EventPageNavigator; +import com.sap.sailing.gwt.ui.shared.SeriesDTO; +import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; +import com.sap.sse.gwt.client.player.Timer; + +public class EventRegattaScheduleFleet extends Composite { + private static EventRegattaScheduleSeriesUiBinder uiBinder = GWT.create(EventRegattaScheduleSeriesUiBinder.class); + + interface EventRegattaScheduleSeriesUiBinder extends UiBinder { + } + + private final FleetDTO fleet; + + @UiField DivElement fleetDiv; + @UiField SpanElement fleetName; + @UiField HTMLPanel racesListPanel; + + public EventRegattaScheduleFleet(StrippedLeaderboardDTO leaderboard, SeriesDTO series, FleetDTO fleet, + Timer timerForClientServerOffset, EventPageNavigator pageNavigator) { + this.fleet = fleet; + + EventRegattaScheduleResources.INSTANCE.css().ensureInjected(); + initWidget(uiBinder.createAndBindUi(this)); + +// if(!fleet.getName().equals(LeaderboardNameConstants.DEFAULT_FLEET_NAME)) { +// fleetName.setInnerText(fleet.getName()); +// fleetDiv.getStyle().setBackgroundColor(fleet.getColor().getAsHtml()); +// } + + List racesOfFleet = getRacesOfFleet(leaderboard, series, fleet); + for(RaceColumnDTO raceColumn: racesOfFleet) { + EventRegattaScheduleRace eventRegattaScheduleRace = new EventRegattaScheduleRace(leaderboard, fleet, raceColumn, timerForClientServerOffset, pageNavigator); + racesListPanel.add(eventRegattaScheduleRace); + } + } + + public EventRegattaScheduleFleet(StrippedLeaderboardDTO leaderboard, Timer timerForClientServerOffset, EventPageNavigator pageNavigator) { + this.fleet = new FleetDTO(LeaderboardNameConstants.DEFAULT_FLEET_NAME, 0, null); + + EventRegattaScheduleResources.INSTANCE.css().ensureInjected(); + initWidget(uiBinder.createAndBindUi(this)); + + fleetName.setInnerText("Races"); +// fleetDiv.getStyle().setBackgroundColor(fleet.getColor().getAsHtml()); + + List racesOfFleet = leaderboard.getRaceList(); + for(RaceColumnDTO raceColumn: racesOfFleet) { + EventRegattaScheduleRace eventRegattaScheduleRace = new EventRegattaScheduleRace(leaderboard, fleet, raceColumn, timerForClientServerOffset, pageNavigator); + racesListPanel.add(eventRegattaScheduleRace); + } + } + + private List getRacesOfFleet(StrippedLeaderboardDTO leaderboard, SeriesDTO series, FleetDTO fleet) { + List racesColumnsOfFleet = new ArrayList(); + int raceColumnCounter = 1; + for (RaceColumnDTO raceColumn : series.getRaceColumns()) { + boolean skipCarryForwardColumn = series.isFirstColumnIsNonDiscardableCarryForward(); + for (FleetDTO fleetOfRaceColumn : series.getFleets()) { + if (fleet.equals(fleetOfRaceColumn) && !(skipCarryForwardColumn == true && raceColumnCounter == 1)) { + // We have to get the race column from the leaderboard, because the race column of the series + // have no tracked race and would be displayed as inactive race. + racesColumnsOfFleet.add(leaderboard.getRaceColumnByName(raceColumn.getName())); + } + } + raceColumnCounter++; + } + return racesColumnsOfFleet; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleFleet.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleFleet.ui.xml new file mode 100644 index 00000000000..61fed4d4c22 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleFleet.ui.xml @@ -0,0 +1,14 @@ + + + + + + +
+
+ +
+
+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleRace.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleRace.java new file mode 100644 index 00000000000..2189ef70178 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleRace.java @@ -0,0 +1,79 @@ +package com.sap.sailing.gwt.home.client.place.event.regattaschedule; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.i18n.shared.DateTimeFormat; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Anchor; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.domain.common.dto.FleetDTO; +import com.sap.sailing.domain.common.dto.RaceColumnDTO; +import com.sap.sailing.domain.common.dto.RaceDTO; +import com.sap.sailing.gwt.home.client.place.event.EventPageNavigator; +import com.sap.sailing.gwt.home.client.place.event.regattaschedule.EventRegattaScheduleResources.LocalCss; +import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; +import com.sap.sse.gwt.client.player.Timer; + +public class EventRegattaScheduleRace extends Composite { + private static EventRegattaScheduleSeriesUiBinder uiBinder = GWT.create(EventRegattaScheduleSeriesUiBinder.class); + + interface EventRegattaScheduleSeriesUiBinder extends UiBinder { + } + + private final FleetDTO fleet; + private final RaceColumnDTO raceColumn; + private final StrippedLeaderboardDTO leaderboard; + + @UiField Anchor raceBox; + @UiField SpanElement raceName; + @UiField SpanElement raceDetails; + + private final DateTimeFormat raceTimeFormat = DateTimeFormat.getFormat("EEE, h:mm a"); + private final EventPageNavigator pageNavigator; + + public EventRegattaScheduleRace(StrippedLeaderboardDTO leaderboard, FleetDTO fleet, RaceColumnDTO raceColumn, Timer timerForClientServerOffset, EventPageNavigator pageNavigator) { + this.leaderboard = leaderboard; + this.fleet = fleet; + this.raceColumn = raceColumn; + this.pageNavigator = pageNavigator; + + LocalCss css = EventRegattaScheduleResources.INSTANCE.css(); + css.ensureInjected(); + initWidget(uiBinder.createAndBindUi(this)); + + raceName.setInnerText(raceColumn.getName()); + + RaceDTO race = raceColumn.getRace(fleet); + if(race != null) { + boolean live = raceColumn.isLive(fleet, timerForClientServerOffset.getLiveTimePointInMillis()); + + // tracked race + raceBox.getElement().addClassName(css.eventregattaschedule_series_fleet_racetracked()); + if(race.trackedRace != null) { + if(race.trackedRace.startOfTracking != null) { + raceDetails.setInnerText(raceTimeFormat.format(race.trackedRace.startOfTracking)); + } else { + raceDetails.setInnerText("tracked"); + } + if(live) { + raceBox.getElement().setAttribute("data-live", "data-live"); + } + } + } else { + raceBox.getElement().addClassName(css.eventregattaschedule_series_fleet_raceuntracked()); + raceDetails.setInnerText("untracked"); + } + } + + @UiHandler("raceBox") + public void goToRaceboard(ClickEvent e) { + RaceDTO race = raceColumn.getRace(fleet); + if(race != null && race.trackedRace != null) { + pageNavigator.openRaceViewer(leaderboard, race); + } + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleRace.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleRace.ui.xml new file mode 100644 index 00000000000..38c46324eaf --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleRace.ui.xml @@ -0,0 +1,14 @@ + + + + + + + +
+
+
+
+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleSeries.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleSeries.java new file mode 100644 index 00000000000..ded215cb5f1 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleSeries.java @@ -0,0 +1,39 @@ +package com.sap.sailing.gwt.home.client.place.event.regattaschedule; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTMLPanel; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.domain.common.dto.FleetDTO; +import com.sap.sailing.gwt.home.client.place.event.EventPageNavigator; +import com.sap.sailing.gwt.ui.shared.SeriesDTO; +import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; +import com.sap.sse.gwt.client.player.Timer; + +public class EventRegattaScheduleSeries extends Composite { + private static EventRegattaScheduleSeriesUiBinder uiBinder = GWT.create(EventRegattaScheduleSeriesUiBinder.class); + + interface EventRegattaScheduleSeriesUiBinder extends UiBinder { + } + + @UiField SpanElement seriesName; + @UiField SpanElement seriesDate; + @UiField HTMLPanel fleetsListPanel; + + public EventRegattaScheduleSeries(StrippedLeaderboardDTO leaderboard, SeriesDTO series, Timer timerForClientServerOffset, EventPageNavigator pageNavigator) { + EventRegattaScheduleResources.INSTANCE.css().ensureInjected(); + initWidget(uiBinder.createAndBindUi(this)); + + seriesName.setInnerText(series.getName()); + seriesDate.setInnerText("Some series data"); + + for(FleetDTO fleet: series.getFleets()) { + EventRegattaScheduleFleet eventRegattaScheduleFleet = new EventRegattaScheduleFleet(leaderboard, series, fleet, timerForClientServerOffset, pageNavigator); + fleetsListPanel.add(eventRegattaScheduleFleet); + } + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleSeries.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleSeries.ui.xml new file mode 100644 index 00000000000..8298091c965 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/regattaschedule/EventRegattaScheduleSeries.ui.xml @@ -0,0 +1,15 @@ + + + + + + +
+

+ + +
+
+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.css index e69de29bb2d..d7258c42961 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.css @@ -0,0 +1,116 @@ +.eventteasercontainer { + font-size: 15px; + font-size: 1rem; + text-align: center; + width: 100%; +} +.eventteaser { + font-size: 15px; + font-size: 1rem; + display: inline-block; + margin-bottom: 3em; + text-align: left; + max-width: 100%; +} +.eventteaser:hover { + text-decoration: none; +} +.eventteaser:hover .eventteaser_name { + text-decoration: underline; +} +.eventteaser:hover .eventteaser_image { + opacity: 0.9; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)"; + filter: literal("alpha(opacity=90)"); +} +.eventteaser_image { + position: relative; + display: inline-block; + max-width: 100%; +} +.eventteaser_series { + position: absolute; + bottom: 0; + right: 0; +} +.eventteaser_name { + font-size: 1.466666666666667em; + font-weight: bold; + color: #008fcc; + margin-top: 0.333333333333333em; +} +.eventteaser_location { + color: #222; +} +.eventsoverviewnavigation { + font-size: 15px; + font-size: 1rem; +} +.eventsoverviewnavigation .gridalternator { + overflow: visible; +} +.eventsoverviewrecent { + font-size: 15px; + font-size: 1rem; + padding-top: 2em; +} +.eventsoverviewrecent_year { + border-bottom: 1px solid #ccc; + transiton: opacity 0.1s; +} +.eventsoverviewrecent_year:nth-child\(even\) { + background: #f8f8f8; +} +.eventsoverviewrecent_year:nth-child\(even\) .eventsoverviewrecent_year_header:hover, +.eventsoverviewrecent_year:nth-child\(even\) .eventsoverviewrecent_year_header:focus { + background-color: #f3f3f3; +} +.eventsoverviewrecent_yearcollapsed .eventsoverviewrecent_year_header_info_arrow_image { + -webkit-transform: rotate(0deg); + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); +} +.eventsoverviewrecent_year_header { + padding: 0.666666666666667em; + cursor: pointer; +} +.eventsoverviewrecent_year_header:hover, +.eventsoverviewrecent_year_header:focus { + background-color: #fcfcfc; +} +.eventsoverviewrecent_year_header:hover .eventsoverviewrecent_year_header_title, +.eventsoverviewrecent_year_header:focus .eventsoverviewrecent_year_header_title { + text-decoration: underline; +} +.eventsoverviewrecent_year_header_title { + margin-bottom: 0; +} +.eventsoverviewrecent_year_header_info { + float: right; +} +.eventsoverviewrecent_year_header_info_arrow { + padding: 0.466666666666667em 1.133333333333333em; +} +.eventsoverviewrecent_year_header_info_arrow_image { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); + transiton: transform 0.4s; +} +.eventsoverviewrecent_year_header_info_item { + border-right: 1px solid #ccc; + padding: 0.466666666666667em 1.133333333333333em; +} +.eventsoverviewrecent_year_header_info_item_value { + font-weight: 700; + color: #008fcc; + margin-right: 0.533333333333333em; +} +.eventsoverviewrecent_year_content { + margin-top: 0.666666666666667em; + padding-bottom: 1.333333333333333em; +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.java index d8ee4613ea9..9a515d8713b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.java @@ -13,7 +13,6 @@ import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.home.client.DateUtil; import com.sap.sailing.gwt.home.client.app.PlaceNavigator; -import com.sap.sailing.gwt.home.client.shared.recentevent.RecentEvents; import com.sap.sailing.gwt.ui.shared.EventBaseDTO; public class EventsOverviewRecent extends Composite { @@ -25,13 +24,13 @@ public class EventsOverviewRecent extends Composite { private final PlaceNavigator navigator; - @UiField HTMLPanel htmlPanel; + @UiField HTMLPanel recentEventsPerYearPanel; - private final Map recentEventsComposites; + private final Map recentEventsComposites; public EventsOverviewRecent(PlaceNavigator navigator) { this.navigator = navigator; - recentEventsComposites = new HashMap(); + recentEventsComposites = new HashMap(); EventsOverviewRecentResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); @@ -39,26 +38,33 @@ public class EventsOverviewRecent extends Composite { public void updateEvents(Map> recentEventsOrderedByYear) { // remove old widgets - htmlPanel.clear(); + recentEventsPerYearPanel.clear(); recentEventsComposites.clear(); // recent events of this year Date now = new Date(); int currentYear = DateUtil.getYear(now); + boolean oneYearIsExpanded = false; if(recentEventsOrderedByYear.get(currentYear) != null) { - RecentEvents recentEvents = new RecentEvents(navigator); - recentEvents.setEvents(recentEventsOrderedByYear.get(currentYear), null); - htmlPanel.add(recentEvents); - recentEventsComposites.put(currentYear, recentEvents); + EventsOverviewRecentYear recentEventsOfOneYear = new EventsOverviewRecentYear(currentYear, recentEventsOrderedByYear.get(currentYear), navigator); + recentEventsPerYearPanel.add(recentEventsOfOneYear); + recentEventsComposites.put(currentYear, recentEventsOfOneYear); + recentEventsOfOneYear.showContent(); + oneYearIsExpanded = true; } currentYear--; while (currentYear > 2010) { if(recentEventsOrderedByYear.get(currentYear) != null) { - RecentEvents recentEvents = new RecentEvents(navigator); - recentEvents.setEvents(recentEventsOrderedByYear.get(currentYear), String.valueOf(currentYear)); - htmlPanel.add(recentEvents); - recentEventsComposites.put(currentYear, recentEvents); + EventsOverviewRecentYear recentEventsOfOneYear = new EventsOverviewRecentYear(currentYear, recentEventsOrderedByYear.get(currentYear), navigator); + recentEventsPerYearPanel.add(recentEventsOfOneYear); + recentEventsComposites.put(currentYear, recentEventsOfOneYear); + if(oneYearIsExpanded == true) { + recentEventsOfOneYear.hideContent(); + } else { + recentEventsOfOneYear.showContent(); + oneYearIsExpanded = true; + } } currentYear--; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.ui.xml index 4a47f2e0a93..e700ec4e1b0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecent.ui.xml @@ -5,7 +5,10 @@ - - + + +
+ +
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentResources.java index b01aa9a5e54..7886298d3e7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentResources.java @@ -11,5 +11,24 @@ public interface EventsOverviewRecentResources extends ClientBundle { LocalCss css(); public interface LocalCss extends CssResource { + String eventteasercontainer(); + String eventteaser(); + String eventteaser_name(); + String eventteaser_image(); + String eventteaser_series(); + String eventteaser_location(); + String eventsoverviewnavigation(); + String gridalternator(); + String eventsoverviewrecent(); + String eventsoverviewrecent_year(); + String eventsoverviewrecent_year_header(); + String eventsoverviewrecent_yearcollapsed(); + String eventsoverviewrecent_year_header_info_arrow_image(); + String eventsoverviewrecent_year_header_title(); + String eventsoverviewrecent_year_header_info(); + String eventsoverviewrecent_year_header_info_arrow(); + String eventsoverviewrecent_year_header_info_item(); + String eventsoverviewrecent_year_header_info_item_value(); + String eventsoverviewrecent_year_content(); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentYear.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentYear.java new file mode 100644 index 00000000000..d7d1117ac49 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentYear.java @@ -0,0 +1,84 @@ +package com.sap.sailing.gwt.home.client.place.events.recent; + +import java.util.List; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTMLPanel; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.home.client.app.PlaceNavigator; +import com.sap.sailing.gwt.home.client.shared.recentevent.RecentEvent; +import com.sap.sailing.gwt.ui.shared.EventBaseDTO; + +public class EventsOverviewRecentYear extends Composite { + + interface EventsOverviewUiBinder extends UiBinder { + } + + private static EventsOverviewUiBinder uiBinder = GWT.create(EventsOverviewUiBinder.class); + + @UiField SpanElement year; + @UiField SpanElement eventsCount; + @UiField SpanElement countriesCount; + @UiField SpanElement sailorsCount; + @UiField SpanElement trackedRacesCount; + @UiField HTMLPanel recentEventsTeaserPanel; + @UiField HTMLPanel contentDiv; + @UiField HTMLPanel headerDiv; + + private boolean isContentVisible; + + public EventsOverviewRecentYear(Integer year, List events, PlaceNavigator navigator) { + EventsOverviewRecentResources.INSTANCE.css().ensureInjected(); + initWidget(uiBinder.createAndBindUi(this)); + + this.year.setInnerText(String.valueOf(year)); + this.eventsCount.setInnerText(String.valueOf(events.size())); + this.countriesCount.setInnerText("tbd."); + this.sailorsCount.setInnerText("tbd."); + this.trackedRacesCount.setInnerText("tbd."); + + for(EventBaseDTO eventDTO: events) { + RecentEvent recentEvent = new RecentEvent(navigator); + recentEvent.setEvent(eventDTO); + recentEventsTeaserPanel.add(recentEvent); + } + isContentVisible = true; + + headerDiv.addDomHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + onHeaderCicked(); + } + }, ClickEvent.getType()); + } + + private void onHeaderCicked() { + isContentVisible = !isContentVisible; + updateContentVisibility(); + } + + public void hideContent() { + isContentVisible = false; + updateContentVisibility(); + } + + public void showContent() { + isContentVisible = true; + updateContentVisibility(); + } + + private void updateContentVisibility() { + contentDiv.setVisible(isContentVisible); + if(isContentVisible) { + headerDiv.getElement().removeClassName(EventsOverviewRecentResources.INSTANCE.css().eventsoverviewrecent_yearcollapsed()); + } else { + headerDiv.getElement().addClassName(EventsOverviewRecentResources.INSTANCE.css().eventsoverviewrecent_yearcollapsed()); + } + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentYear.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentYear.ui.xml new file mode 100644 index 00000000000..316091d492f --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/events/recent/EventsOverviewRecentYear.ui.xml @@ -0,0 +1,57 @@ + + + + + + + + +
+ +
+
+

+
+
+ + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/SmartphoneStartView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/SmartphoneStartView.java index 8974f2d8338..c19df307ee4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/SmartphoneStartView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/SmartphoneStartView.java @@ -13,7 +13,9 @@ import com.sap.sailing.gwt.home.client.shared.mainmedia.MainMedia; import com.sap.sailing.gwt.home.client.shared.mainsponsors.MainSponsors; import com.sap.sailing.gwt.home.client.shared.socialfooter.SocialFooter; import com.sap.sailing.gwt.home.client.shared.stage.Stage; +import com.sap.sailing.gwt.home.client.shared.stage.StageEventType; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sse.common.Util.Pair; public class SmartphoneStartView extends Composite implements StartView { private static StartPageMobileViewUiBinder uiBinder = GWT.create(StartPageMobileViewUiBinder.class); @@ -21,13 +23,14 @@ public class SmartphoneStartView extends Composite implements StartView { interface StartPageMobileViewUiBinder extends UiBinder { } - @UiField Stage stage; + @UiField(provided=true) Stage stage; @UiField(provided=true) MainSponsors mainSponsors; @UiField(provided=true) MainEvents mainEvents; @UiField(provided=true) MainMedia mainMedia; @UiField SocialFooter socialFooter; public SmartphoneStartView(PlaceNavigator navigator) { + stage = new Stage(navigator); mainSponsors = new MainSponsors(navigator); mainEvents = new MainEvents(navigator); mainMedia = new MainMedia(navigator); @@ -35,8 +38,8 @@ public class SmartphoneStartView extends Composite implements StartView { } @Override - public void setFeaturedEvent(EventDTO featuredEvent) { - stage.setFeaturedEvent(featuredEvent); + public void setFeaturedEvents(List> featuredEvents) { + stage.setFeaturedEvents(featuredEvents); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/StartActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/StartActivity.java index e3641f43a9c..9f9fef4b4c9 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/StartActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/StartActivity.java @@ -8,7 +8,9 @@ import com.google.gwt.activity.shared.AbstractActivity; import com.google.gwt.event.shared.EventBus; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.sap.sailing.gwt.home.client.shared.stage.StageEventType; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sse.common.Util.Pair; public class StartActivity extends AbstractActivity { private final StartClientFactory clientFactory; @@ -36,22 +38,49 @@ public class StartActivity extends AbstractActivity { @SuppressWarnings("deprecation") protected void fillStartPageEvents(StartView view, List events) { - EventDTO featuredEvent = null; - List recentEvents = new ArrayList(); + List> featuredEvents = new ArrayList>(); + + List recentEventsOfSameYear = new ArrayList(); + List upcomingSoonEvents = new ArrayList(); + List popularEvents = new ArrayList(); Date now = new Date(); int currentYear = now.getYear(); + final int MAX_STAGE_EVENTS = 2; + final long TWO_WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7; for(EventDTO event: events) { + // ignore events with no start and end date if(event.startDate != null && event.endDate != null) { - if(featuredEvent == null && event.startDate.after(now)) { - featuredEvent = event; - view.setFeaturedEvent(event); - } - if(event.endDate.before(now) && event.endDate.getYear() == currentYear) { - recentEvents.add(event); + if (now.after(event.startDate) && now.before(event.endDate)) { + featuredEvents.add(new Pair(StageEventType.RUNNING, event)); + } else if (event.startDate.after(now) && event.startDate.getTime() - now.getTime() < TWO_WEEK_IN_MS) { + upcomingSoonEvents.add(event); + } else if (event.endDate.before(now) && event.endDate.getYear() == currentYear) { + recentEventsOfSameYear.add(event); } } } - view.setRecentEvents(recentEvents); + + if(featuredEvents.size() < MAX_STAGE_EVENTS) { + fillingUpEventsList(MAX_STAGE_EVENTS, featuredEvents, StageEventType.UPCOMING_SOON, upcomingSoonEvents); + } + if(featuredEvents.size() < MAX_STAGE_EVENTS) { + fillingUpEventsList(MAX_STAGE_EVENTS, featuredEvents, StageEventType.POPULAR, popularEvents); + } + // fallback for the case we did not find any events + if(featuredEvents.size() < MAX_STAGE_EVENTS) { + fillingUpEventsList(MAX_STAGE_EVENTS, featuredEvents, StageEventType.POPULAR, recentEventsOfSameYear); + } + + view.setFeaturedEvents(featuredEvents); + view.setRecentEvents(recentEventsOfSameYear); + } + + private void fillingUpEventsList(int maxAmountOfElements, List> resultList, StageEventType type, List listToTakeElementsFrom) { + int maxElementsToFill = maxAmountOfElements - resultList.size(); + int elementsToTransfer = listToTakeElementsFrom.size() > maxElementsToFill ? maxElementsToFill : listToTakeElementsFrom.size(); + for(int i = 0; i < elementsToTransfer; i++) { + resultList.add(new Pair(type, listToTakeElementsFrom.get(i))); + } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/StartView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/StartView.java index e14799f0990..1a22a8e509c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/StartView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/StartView.java @@ -3,12 +3,14 @@ package com.sap.sailing.gwt.home.client.place.start; import java.util.List; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.home.client.shared.stage.StageEventType; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sse.common.Util.Pair; public interface StartView { Widget asWidget(); - void setFeaturedEvent(EventDTO featuredEvent); + void setFeaturedEvents(List> featuredEvents); void setRecentEvents(List recentEvents); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/TabletAndDesktopStartView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/TabletAndDesktopStartView.java index 1fb9395a7f4..bdfa661fb0a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/TabletAndDesktopStartView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/TabletAndDesktopStartView.java @@ -10,10 +10,11 @@ import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.home.client.app.PlaceNavigator; import com.sap.sailing.gwt.home.client.shared.mainevents.MainEvents; import com.sap.sailing.gwt.home.client.shared.mainmedia.MainMedia; -import com.sap.sailing.gwt.home.client.shared.mainsponsors.MainSponsors; import com.sap.sailing.gwt.home.client.shared.socialfooter.SocialFooter; import com.sap.sailing.gwt.home.client.shared.stage.Stage; +import com.sap.sailing.gwt.home.client.shared.stage.StageEventType; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sse.common.Util.Pair; public class TabletAndDesktopStartView extends Composite implements StartView { private static StartPageViewUiBinder uiBinder = GWT.create(StartPageViewUiBinder.class); @@ -21,14 +22,15 @@ public class TabletAndDesktopStartView extends Composite implements StartView { interface StartPageViewUiBinder extends UiBinder { } - @UiField Stage stage; - @UiField(provided=true) MainSponsors mainSponsors; + @UiField(provided=true) Stage stage; +// @UiField(provided=true) MainSponsors mainSponsors; @UiField(provided=true) MainEvents mainEvents; @UiField(provided=true) MainMedia mainMedia; @UiField SocialFooter socialFooter; public TabletAndDesktopStartView(PlaceNavigator navigator) { - mainSponsors = new MainSponsors(navigator); + stage = new Stage(navigator); +// mainSponsors = new MainSponsors(navigator); mainEvents = new MainEvents(navigator); mainMedia = new MainMedia(navigator); @@ -36,8 +38,8 @@ public class TabletAndDesktopStartView extends Composite implements StartView { } @Override - public void setFeaturedEvent(EventDTO featuredEvent) { - stage.setFeaturedEvent(featuredEvent); + public void setFeaturedEvents(List> featuredEvents) { + stage.setFeaturedEvents(featuredEvents); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/TabletAndDesktopStartView.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/TabletAndDesktopStartView.ui.xml index 750f7d032ac..fe17dfbe93c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/TabletAndDesktopStartView.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/start/TabletAndDesktopStartView.ui.xml @@ -6,7 +6,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/EventDatesFormatterUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/EventDatesFormatterUtil.java index 8fb8118c819..add95120f06 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/EventDatesFormatterUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/EventDatesFormatterUtil.java @@ -19,9 +19,9 @@ public class EventDatesFormatterUtil { public static String formatDateRangeWithYear(Date from, Date to) { String result = ""; if(from.getMonth() == to.getMonth()) { - result = monthFormat.format(from) + " " + dayFormat.format(from) + " - " + dayFormat.format(to) + " " + yearFormat.format(from); + result = monthFormat.format(from) + " " + dayFormat.format(from) + " - " + dayFormat.format(to) + ", " + yearFormat.format(from); } else { - result = dayAndMonthFormat.format(from) + " - " + dayAndMonthFormat.format(to) + " " + yearFormat.format(from); + result = dayAndMonthFormat.format(from) + " - " + dayAndMonthFormat.format(to) + ", " + yearFormat.format(from); } return result; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/eventsponsors/EventSponsors.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/eventsponsors/EventSponsors.java index 4dd4fb88ca9..27e3d048b54 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/eventsponsors/EventSponsors.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/eventsponsors/EventSponsors.java @@ -9,7 +9,6 @@ import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.ui.shared.EventBaseDTO; public class EventSponsors extends Composite { private static EventSponsorsPanelUiBinder uiBinder = GWT.create(EventSponsorsPanelUiBinder.class); @@ -28,15 +27,17 @@ public class EventSponsors extends Composite { eventSponsorComposites = new ArrayList(); } - public void setEventSponsors(EventBaseDTO event) { + public void setEventSponsors(List sponsorImageUrls) { sponsorsPlaceholder.clear(); eventSponsorComposites.clear(); - for (String sponsorImageUrl : event.getSponsorImageURLs()) { - EventSponsor eventSponor = new EventSponsor(null /* name */, sponsorImageUrl, null /* link */); + if(sponsorImageUrls != null) { + for (String sponsorImageUrl : sponsorImageUrls) { + EventSponsor eventSponor = new EventSponsor(null /* name */, sponsorImageUrl, null /* link */); - eventSponsorComposites.add(eventSponor); - sponsorsPlaceholder.add(eventSponor); + eventSponsorComposites.add(eventSponor); + sponsorsPlaceholder.add(eventSponor); + } } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.java index c052e43b701..2cd34270ae7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.java @@ -1,12 +1,18 @@ package com.sap.sailing.gwt.home.client.shared.footer; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.SpanElement; import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.http.client.UrlBuilder; import com.google.gwt.i18n.client.LocaleInfo; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; @@ -15,24 +21,47 @@ public class Footer extends Composite { private static FooterPanelUiBinder uiBinder = GWT.create(FooterPanelUiBinder.class); @UiField Anchor changeLanguageLink; - @UiField SpanElement currentLanguage; - - private LocaleInfo currentLocale; + private final Map localeAndLanguages; + + /** set-configuration-property name='locale.searchorder' value='queryparam,cookie,useragent' /> */ + interface FooterPanelUiBinder extends UiBinder { } public Footer() { + localeAndLanguages = new HashMap(); + localeAndLanguages.put("default", "English"); + localeAndLanguages.put("de", "Deutsch"); + FooterResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); - currentLocale = LocaleInfo.getCurrentLocale(); - - currentLanguage.setInnerHTML(currentLocale.getLocaleName()); + updateUI(); } @UiHandler("changeLanguageLink") public void changeLanguage(ClickEvent e) { + String selectedLanguage = changeLanguageLink.getText(); + String selectedLocale = null; + for (Entry entry: localeAndLanguages.entrySet()) { + if (entry.getValue().equals(selectedLanguage)) { + selectedLocale = entry.getKey(); + } + } + if(selectedLocale != null) { + UrlBuilder builder = Location.createUrlBuilder().setParameter("locale", selectedLocale); + Window.Location.replace(builder.buildString()); + } } + + private void updateUI() { + LocaleInfo currentLocale = LocaleInfo.getCurrentLocale(); + HashMap languagesToSelectFrom = new HashMap(localeAndLanguages); + languagesToSelectFrom.remove(currentLocale.getLocaleName()); + if(languagesToSelectFrom.size() == 1) { + changeLanguageLink.setText(languagesToSelectFrom.values().iterator().next()); + } + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml index de21ed59bf7..3baa3c934b0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/footer/Footer.ui.xml @@ -20,7 +20,7 @@
- :
+ :
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/header/Header.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/header/Header.java index 36600d638b7..9da82dc1fb3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/header/Header.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/header/Header.java @@ -23,13 +23,12 @@ public class Header extends Composite { @UiField Anchor startPageLink; @UiField Anchor eventsPageLink; @UiField Anchor solutionsPageLink; - @UiField Anchor sponsoringPageLink; +// @UiField Anchor sponsoringPageLink; @UiField TextBox searchText; @UiField Button searchButton; - - private final List links; + private final List links; private final PlaceNavigator navigator; interface HeaderUiBinder extends UiBinder { @@ -41,7 +40,7 @@ public class Header extends Composite { this.navigator = navigator; HeaderResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); - links = Arrays.asList(new Anchor[] { startPageLink, eventsPageLink, solutionsPageLink, sponsoringPageLink }); + links = Arrays.asList(new Anchor[] { startPageLink, eventsPageLink, solutionsPageLink }); searchText.getElement().setAttribute("placeholder", "Search SAPSailing.com"); searchText.addKeyPressHandler(new KeyPressHandler() { @@ -70,10 +69,10 @@ public class Header extends Composite { navigator.goToSolutions(); } - @UiHandler("sponsoringPageLink") - public void goToSponsoring(ClickEvent e) { - navigator.goToSponsoring(); - } +// @UiHandler("sponsoringPageLink") +// public void goToSponsoring(ClickEvent e) { +// navigator.goToSponsoring(); +// } @UiHandler("searchButton") void searchButtonClick(ClickEvent event) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/header/Header.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/header/Header.ui.xml index c29ce3a17d1..1204cd6f979 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/header/Header.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/header/Header.ui.xml @@ -19,9 +19,10 @@ styleName="{local_res.css.sitenavigation_link}" text="{i18n.events}" href="javascript:;"/> +
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.css index b10cdf3afff..d523037693f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.css @@ -1,92 +1,115 @@ -/** - * Websites main media element - */ .media { - background: #f8f8f8; - font-size: 16px; - font-size: 1rem; + font-size: 15px; + font-size: 1rem; } -.media_photo { - width: 100%; - height: 100%; + +.media_swipecontainer { + position: relative; + width: 830px; + height: 550px; + margin: 0 auto; + overflow: hidden; } -.media_slideshow { - position: relative; - height: 550px; - width: 830px; - margin: 0 auto; + +.media_swipewrapper { } + +.media_swiperslide { + display: inline-block; + background: no-repeat center center; + -webkit-background-size: contain; + -moz-background-size: contain; + -o-background-size: contain; + background-size: contain; +} + .media_slideshow_controls { - position: absolute; - background-position: 0 0; - background-repeat: no-repeat; - cursor: pointer; + position: absolute; + background-position: 0 0; + background-repeat: no-repeat; + cursor: pointer; + z-index: 10; } -.media_slideshow_controlsnext, + +.media_slideshow_controlsnext,.media_slideshow_controlsprev { + top: 50%; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); + width: 60px; + height: 60px; + background-image: url("images/home/media-controls__arrows.png"); +} + .media_slideshow_controlsprev { - top: 50%; - -webkit-transform: translate(0, -50%); - -moz-transform: translate(0, -50%); - -o-transform: translate(0, -50%); - -ms-transform: translate(0, -50%); - transform: translate(0, -50%); - width: 60px; - height: 60px; - background-image: url("images/home/media-controls__arrows.png"); -} -.media_slideshow_controlsprev { - left: 0; - background-position: 0 0; + left: 0; + background-position: 0 0; } + .media_slideshow_controlsprev:hover { - background-position: 0 100%; + background-position: 0 100%; } + .media_slideshow_controlsnext { - right: 0; - background-position: 100% 0; + right: 0; + background-position: 100% 0; } + .media_slideshow_controlsnext:hover { - background-position: 100% 100%; + background-position: 100% 100%; } + .media_slideshow_controlsfullsize { - background-image: url("images/home/media-controls__fullsize.png"); - right: 0; - bottom: 0; - width: 40px; - height: 40px; + background-image: url("images/home/media-controls__fullsize.png"); + right: 0; + bottom: 0; + width: 40px; + height: 40px; } + .mediavideos { - background: #333; - color: #fff; + background: #333; + color: #fff; } + .mediavideos .mainsection_header_title { - color: #fff; + color: #fff; } + .videopreview { - font-size: 16px; - font-size: 1rem; - margin-bottom: 2.5em; - cursor: pointer; + font-size: 15px; + font-size: 1rem; + margin-bottom: 2.666666666666667em; + cursor: pointer; } + .videopreview:before { - content: ' '; - position: absolute; - left: 50%; - top: 70px; - -webkit-transform: translate(-50%, 0); - -moz-transform: translate(-50%, 0); - -o-transform: translate(-50%, 0); - -ms-transform: translate(-50%, 0); - transform: translate(-50%, 0); - width: 69px; - height: 69px; - background: url("images/home/video__preview--play.png"); - -webkit-background-size: contain; - -moz-background-size: contain; - background-size: contain; + content: ' '; + position: absolute; + left: 50%; + top: 70px; + -webkit-transform: translate(-50%, 0); + -moz-transform: translate(-50%, 0); + -o-transform: translate(-50%, 0); + -ms-transform: translate(-50%, 0); + transform: translate(-50%, 0); + width: 69px; + height: 69px; + background: url("images/home/video__preview--play.png"); + -webkit-background-size: contain; + -moz-background-size: contain; + background-size: contain; } + .videopreview_title { - font-size: 1.375em; - font-weight: bold; - margin: 0; + font-size: 1.466666666666667em; + font-weight: bold; + margin: 0; + color: #fff; } + +.videopreview time { + display: block; +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.java index b8ea0418bf1..642b4dfbbae 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.java @@ -1,30 +1,34 @@ package com.sap.sailing.gwt.home.client.shared.mainmedia; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Random; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; +import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTMLPanel; +import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.home.client.app.PlaceNavigator; +import com.sap.sailing.gwt.idangerous.Swiper; import com.sap.sailing.gwt.ui.shared.EventDTO; public class MainMedia extends Composite { + + private static final MainMediaResources.LocalCss STYLES = MainMediaResources.INSTANCE.css(); - @UiField DivElement photoImage; + @UiField HTMLPanel videosPanel; + @UiField DivElement videoLightBoxData; + + @UiField HTMLPanel mediaSlides; - @UiField(provided=true) RecentEventVideo eventVideo1; - @UiField(provided=true) RecentEventVideo eventVideo2; - @UiField(provided=true) RecentEventVideo eventVideo3; - - private List recentEvents; - - private final String basePathToImages = "http://static.sapsailing.com/newhome/media/"; - - private String[] images = { "main-media-photo-1.jpg" }; + private Swiper swiper; interface MainMediaUiBinder extends UiBinder { } @@ -32,38 +36,61 @@ public class MainMedia extends Composite { private static MainMediaUiBinder uiBinder = GWT.create(MainMediaUiBinder.class); public MainMedia(PlaceNavigator navigator) { - eventVideo1 = new RecentEventVideo(navigator); - eventVideo2 = new RecentEventVideo(navigator); - eventVideo3 = new RecentEventVideo(navigator); MainMediaResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); - String imagePath = "url(" + basePathToImages + images[0] + ")"; - photoImage.getStyle().setBackgroundImage(imagePath); - - recentEvents = new ArrayList(); } - public void setRecentEvents(List theRecentEvents) { - recentEvents.clear(); - recentEvents.addAll(theRecentEvents); + public void setRecentEvents(List recentEvents) { + List photoGalleryUrls = new ArrayList(); + String lightBoxData = ""; - int size = recentEvents.size(); - if(size > 0) { - eventVideo1.setEvent(recentEvents.get(0)); - } else { - eventVideo1.setVisible(false); + int videoCounter = 0; + for(EventDTO event: recentEvents) { + photoGalleryUrls.addAll(event.getPhotoGalleryImageURLs()); + + if(event.getVideoURLs().size() > 0 && videoCounter < 3) { + MainMediaVideo video = new MainMediaVideo(event); + lightBoxData += video.getDataForLightBox(); + videosPanel.add(video); + videoCounter++; + } } - if(size > 1) { - eventVideo2.setEvent(recentEvents.get(1)); - } else { - eventVideo2.setVisible(false); + + videoLightBoxData.setInnerText(lightBoxData); + + // shuffle the image url list (Remark: Collections.shuffle() is not implemented in GWT) + int gallerySize = photoGalleryUrls.size(); + Random random = new Random(gallerySize); + for(int i = 0; i < gallerySize; i++) { + Collections.swap(photoGalleryUrls, i, random.nextInt(gallerySize)); } - if(size > 2) { - eventVideo3.setEvent(recentEvents.get(2)); - } else { - eventVideo3.setVisible(false); + + for(String url : photoGalleryUrls) { + SimplePanel imageContainer = new SimplePanel(); + imageContainer.addStyleName(STYLES.media_swiperslide()); + String image = "url(" + url + ")"; + imageContainer.getElement().getStyle().setBackgroundImage(image); + mediaSlides.add(imageContainer); + } + + this.swiper = Swiper.createWithDefaultOptions(STYLES.media_swipecontainer(), STYLES.media_swipewrapper(), STYLES.media_swiperslide()); + + } + + @UiHandler("nextPictureLink") + public void nextStageTeaserLinkClicked(ClickEvent e) { + if (this.swiper != null) { + this.swiper.swipeNext(); } } + + @UiHandler("prevPictureLink") + public void prevStageTeaserLinkClicked(ClickEvent e) { + if (this.swiper != null) { + this.swiper.swipePrev(); + } + } + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.ui.xml index 5043e1ded14..f77e4f6babb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMedia.ui.xml @@ -1,45 +1,52 @@ - - - - - -
-
+ + + + + + + +
+
-
-

Sailing loves Photography

-

Get lost in the latest and most beautiful impressions from your favorite sailing event.

-
+
+

+ +

+

+ +

+
-
-
+
+
-
-
-
-
-
-
+
+ + + +
+
-
-
-
+
+
-
-

Recent Video Entries

-

Immerse yourself in the world of sailing and check out our latest events for more videos.

-
+
+

+ +

+

+ +

+
+
+
+
+ +
-
- - - -
-
- + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaResources.java index db9f2033ba9..d6f8749985a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaResources.java @@ -12,8 +12,9 @@ public interface MainMediaResources extends ClientBundle { public interface LocalCss extends CssResource { String media(); - String media_photo(); - String media_slideshow(); + String media_swipecontainer(); + String media_swipewrapper(); + String media_swiperslide(); String media_slideshow_controls(); String media_slideshow_controlsnext(); String media_slideshow_controlsprev(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.java new file mode 100644 index 00000000000..3e0a234a006 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.java @@ -0,0 +1,66 @@ +package com.sap.sailing.gwt.home.client.shared.mainmedia; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.ImageElement; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.shared.EventDTO; + +public class MainMediaVideo extends Composite { + + + interface MainMediaVideoUiBinder extends UiBinder { + } + + private static MainMediaVideoUiBinder uiBinder = GWT.create(MainMediaVideoUiBinder.class); + + private final static String DEFAULT_VIDEO_THUMB_IMAGE_URL = "http://static.sapsailing.com/ubilabsimages/default/default_video_preview.jpg"; + + @UiField SpanElement videoTime; + @UiField SpanElement videoTitle; + + @UiField ImageElement videoThumbImage; + @UiField Element videoFile; + + // Format: {video.thumb},{video.file},{video.title},video; + private String lightBoxData; + + public MainMediaVideo(EventDTO event) { + MainMediaResources.INSTANCE.css().ensureInjected(); + initWidget(uiBinder.createAndBindUi(this)); + + String videoThumbImageUrl; + if(event.getPhotoGalleryImageURLs().size() > 0) { + videoThumbImageUrl = event.getPhotoGalleryImageURLs().get(0); + } else { + videoThumbImageUrl = DEFAULT_VIDEO_THUMB_IMAGE_URL; + } + videoThumbImage.setSrc(videoThumbImageUrl); + lightBoxData = videoThumbImageUrl + "," + event.getVideoURLs().get(0) + ";"; + + videoTime.setInnerHTML("3:40 min"); + videoTitle.setInnerHTML(event.getName()); + videoFile.setAttribute("data-src", event.getVideoURLs().get(0)); + } + + public String getDataForLightBox() { + return lightBoxData; + } + +// @UiHandler("eventMediaPageLink") +// public void goToEventMediaPage(ClickEvent e) { +// if(event.getBaseURL().contains("localhost") || event.getBaseURL().contains("127.0.0.1")) { +// navigator.goToEvent(event.id.toString()); +// } else { +// EventPlace eventPlace = new EventPlace(event.id.toString()); +// EventPlace.Tokenizer t = new Tokenizer(); +// String remoteEventUrl = event.getBaseURL() + "/gwt/Home.html#" + EventPlace.class.getSimpleName() + ":" + t.getToken(eventPlace); +// Window.Location.replace(remoteEventUrl); +// } +// } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/RecentEventVideo.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.ui.xml similarity index 51% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/RecentEventVideo.ui.xml rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.ui.xml index 105d3da0acd..346a6dcfa69 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/RecentEventVideo.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/MainMediaVideo.ui.xml @@ -6,14 +6,13 @@ -
-
-
-

-
-
Show More
-
-
-
+ +
+
+
+ +
+
+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/RecentEventVideo.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/RecentEventVideo.java deleted file mode 100644 index b403abfe74e..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/mainmedia/RecentEventVideo.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.sap.sailing.gwt.home.client.shared.mainmedia; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.ImageElement; -import com.google.gwt.dom.client.SpanElement; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.uibinder.client.UiBinder; -import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.uibinder.client.UiHandler; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.Anchor; -import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.home.client.app.PlaceNavigator; -import com.sap.sailing.gwt.home.client.place.event.EventPlace; -import com.sap.sailing.gwt.home.client.place.event.EventPlace.Tokenizer; -import com.sap.sailing.gwt.ui.shared.EventDTO; - -public class RecentEventVideo extends Composite { - - @UiField SpanElement eventVideoLength; - @UiField SpanElement eventName; - @UiField ImageElement eventVideoPreviewImage; - @UiField Anchor eventMediaPageLink; - - private final String defaultVideoImageUrl = "http://static.sapsailing.com/newhome/default_video_preview.jpg"; - - private EventDTO event; - - interface RecentEventVideoUiBinder extends UiBinder { - } - - private static RecentEventVideoUiBinder uiBinder = GWT.create(RecentEventVideoUiBinder.class); - - private final PlaceNavigator navigator; - - public RecentEventVideo(PlaceNavigator navigator) { - this.navigator = navigator; - initWidget(uiBinder.createAndBindUi(this)); - } - - public void setEvent(EventDTO event) { - this.event = event; - updateUI(); - } - - @UiHandler("eventMediaPageLink") - public void goToEventMediaPage(ClickEvent e) { - if(event.getBaseURL().contains("localhost") || event.getBaseURL().contains("127.0.0.1")) { - navigator.goToEvent(event.id.toString()); - } else { - EventPlace eventPlace = new EventPlace(event.id.toString()); - EventPlace.Tokenizer t = new Tokenizer(); - String remoteEventUrl = event.getBaseURL() + "/gwt/Home.html#" + EventPlace.class.getSimpleName() + ":" + t.getToken(eventPlace); - Window.Location.replace(remoteEventUrl); - } - } - - private void updateUI() { - eventName.setInnerText(event.getName()); - - if(event.getVideoURLs().size() == 0) { - eventVideoPreviewImage.setSrc(defaultVideoImageUrl); - } else { - eventVideoPreviewImage.setSrc(event.getVideoURLs().get(0)); - } - } -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/recentevent/RecentEvent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/recentevent/RecentEvent.java index 572ab5bdf71..b621c4dc5ef 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/recentevent/RecentEvent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/recentevent/RecentEvent.java @@ -7,13 +7,10 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; -import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.home.client.app.PlaceNavigator; -import com.sap.sailing.gwt.home.client.place.event.EventPlace; -import com.sap.sailing.gwt.home.client.place.event.EventPlace.Tokenizer; import com.sap.sailing.gwt.home.client.shared.EventDatesFormatterUtil; import com.sap.sailing.gwt.ui.shared.EventBaseDTO; @@ -27,7 +24,7 @@ public class RecentEvent extends Composite { private EventBaseDTO event; - private final String defaultImageUrl = "http://static.sapsailing.com/newhome/default_event_photo.jpg"; + private final String defaultImageUrl = "http://static.sapsailing.com/ubilabsimages/default/default_event_photo.jpg"; interface RecentEventUiBinder extends UiBinder { } @@ -50,14 +47,7 @@ public class RecentEvent extends Composite { @UiHandler("eventOverviewLink") public void goToEventPlace(ClickEvent e) { - if(event.getBaseURL().contains("localhost") || event.getBaseURL().contains("127.0.0.1")) { - navigator.goToEvent(event.id.toString()); - } else { - EventPlace eventPlace = new EventPlace(event.id.toString()); - EventPlace.Tokenizer t = new Tokenizer(); - String remoteEventUrl = event.getBaseURL() + "/gwt/Home.html#" + EventPlace.class.getSimpleName() + ":" + t.getToken(eventPlace); - Window.Location.replace(remoteEventUrl); - } + navigator.goToEvent(event.id.toString(), event.getBaseURL()); } private void updateUI() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/searchresult/SearchResultItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/searchresult/SearchResultItem.java index 0467cc2b906..e0709cba666 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/searchresult/SearchResultItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/searchresult/SearchResultItem.java @@ -6,13 +6,10 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; -import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.home.client.app.PlaceNavigator; -import com.sap.sailing.gwt.home.client.place.event.EventPlace; -import com.sap.sailing.gwt.home.client.place.event.EventPlace.Tokenizer; import com.sap.sailing.gwt.home.client.shared.EventDatesFormatterUtil; import com.sap.sailing.gwt.ui.shared.EventBaseDTO; import com.sap.sailing.gwt.ui.shared.LeaderboardSearchResultDTO; @@ -26,21 +23,28 @@ public class SearchResultItem extends Composite { @UiField Anchor regattaLink; @UiField SpanElement resultRegattaDetails; @UiField SpanElement resultEventDate; + @UiField SpanElement resultEventVenue; @UiField Anchor eventOverviewLink; - private final PlaceNavigator navigator; + private final PlaceNavigator placeNavigator; private LeaderboardSearchResultDTO searchResult; public SearchResultItem(PlaceNavigator navigator, LeaderboardSearchResultDTO searchResult) { - this.navigator = navigator; + this.placeNavigator = navigator; this.searchResult = searchResult; SearchResultResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); - regattaLink.setText(searchResult.getRegattaName()); - resultRegattaDetails.setInnerText("I have no idea yet what to show here..."); + String headlineLink = searchResult.getLeaderboardDisplayName(); + if(headlineLink == null) { + headlineLink = searchResult.getRegattaName() != null ? searchResult.getRegattaName() : searchResult.getLeaderboardName(); + } + + regattaLink.setText(headlineLink); +// resultRegattaDetails.setInnerText("I have no idea yet what to show here..."); eventOverviewLink.setText(searchResult.getEvent().getName()); + resultEventVenue.setInnerText(searchResult.getEvent().venue.getName()); if(searchResult.getEvent().startDate != null) { resultEventDate.setInnerText(EventDatesFormatterUtil.formatDateRangeWithYear(searchResult.getEvent().startDate, searchResult.getEvent().endDate)); } else { @@ -50,21 +54,13 @@ public class SearchResultItem extends Composite { @UiHandler("regattaLink") public void goToRegatta(ClickEvent e) { - Window.alert("Not implemented yet."); + EventBaseDTO event = searchResult.getEvent(); + placeNavigator.goToRegattaOfEvent(event.id.toString(), searchResult.getLeaderboardName(), searchResult.getBaseURL()); } @UiHandler("eventOverviewLink") public void goToEventPlace(ClickEvent e) { EventBaseDTO event = searchResult.getEvent(); - - if(searchResult.getBaseURL().contains("localhost") || searchResult.getBaseURL().contains("127.0.0.1")) { - navigator.goToEvent(event.id.toString()); - } else { - EventPlace eventPlace = new EventPlace(event.id.toString()); - EventPlace.Tokenizer t = new Tokenizer(); - String remoteEventUrl = searchResult.getBaseURL() + "/gwt/Home.html#" + EventPlace.class.getSimpleName() + ":" + t.getToken(eventPlace); - Window.Location.replace(remoteEventUrl); - } + placeNavigator.goToEvent(event.id.toString(), searchResult.getBaseURL()); } - } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/searchresult/SearchResultItem.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/searchresult/SearchResultItem.ui.xml index b4b76e2e6e6..771fcfc84e0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/searchresult/SearchResultItem.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/searchresult/SearchResultItem.ui.xml @@ -13,6 +13,7 @@
+ | |
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/solutions/Solutions.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/solutions/Solutions.ui.xml index d288ccb5802..8110b8fc28e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/solutions/Solutions.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/solutions/Solutions.ui.xml @@ -25,7 +25,8 @@

-

Read More +

+
@@ -36,7 +37,8 @@

-

Start Tour +

+
@@ -66,7 +68,8 @@

-

Learn More +

+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/LiveEventStageTeaser.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/LiveEventStageTeaser.java new file mode 100644 index 00000000000..544d6220826 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/LiveEventStageTeaser.java @@ -0,0 +1,25 @@ +package com.sap.sailing.gwt.home.client.shared.stage; + +import com.google.gwt.dom.client.Style.Display; +import com.google.gwt.dom.client.Style.Visibility; +import com.sap.sailing.gwt.home.client.app.PlaceNavigator; +import com.sap.sailing.gwt.ui.shared.EventDTO; + +public class LiveEventStageTeaser extends StageTeaser { + + public LiveEventStageTeaser(EventDTO event, PlaceNavigator placeNavigator) { + super(event); + + title.setInnerText(event.getName()); + subtitle.setInnerText(event.venue.getName()); + + countDown.getStyle().setDisplay(Display.NONE); + countDown.getStyle().setVisibility(Visibility.HIDDEN); + + bandCount.setAttribute("data-bandcount", "2"); + + stageTeaserBandsPanel.add(new StageTeaserBand(event, placeNavigator)); + stageTeaserBandsPanel.add(new StageTeaserBand(event, placeNavigator)); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/PopularEventStageTeaser.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/PopularEventStageTeaser.java new file mode 100644 index 00000000000..a99430b743f --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/PopularEventStageTeaser.java @@ -0,0 +1,23 @@ +package com.sap.sailing.gwt.home.client.shared.stage; + +import com.google.gwt.dom.client.Style.Display; +import com.google.gwt.dom.client.Style.Visibility; +import com.sap.sailing.gwt.home.client.app.PlaceNavigator; +import com.sap.sailing.gwt.ui.shared.EventDTO; + +public class PopularEventStageTeaser extends StageTeaser { + + public PopularEventStageTeaser(EventDTO event, PlaceNavigator placeNavigator) { + super(event); + + title.setInnerText(event.getName()); + subtitle.setInnerText(event.venue.getName()); + + countDown.getStyle().setDisplay(Display.NONE); + countDown.getStyle().setVisibility(Visibility.HIDDEN); + + bandCount.setAttribute("data-bandcount", "1"); + + stageTeaserBandsPanel.add(new StageTeaserBand(event, placeNavigator)); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.css index b353c6d1a14..f9f3565787d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.css @@ -1,85 +1,261 @@ -/** - * Main stage area - */ -.stage { - display: -webkit-box; - display: -moz-box; - display: -webkit-flex; - display: -ms-flexbox; - display: box; - display: flex; - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - -o-box-orient: vertical; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: start; - -moz-box-pack: start; - -o-box-pack: start; - -ms-flex-pack: start; - -webkit-justify-content: flex-start; - justify-content: flex-start; - font-size: 16px; +.swipercontainer { + margin: 0 auto; + position: relative; + overflow: hidden; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + -o-backface-visibility: hidden; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; + z-index: 1; +} +.swiperwrapper { + position: relative; + width: 100%; + -webkit-transition-property: -webkit-transform, left, top; + -webkit-transition-duration: 0s; + -webkit-transform: translate3d(0px, 0, 0); + -webkit-transition-timing-function: ease; + -moz-transition-property: -moz-transform, left, top; + -moz-transition-duration: 0s; + -moz-transform: translate3d(0px, 0, 0); + -moz-transition-timing-function: ease; + -o-transition-property: -o-transform, left, top; + -o-transition-duration: 0s; + -o-transform: translate3d(0px, 0, 0); + -o-transition-timing-function: ease; + -o-transform: translate(0px, 0px); + -ms-transition-property: -ms-transform, left, top; + -ms-transition-duration: 0s; + -ms-transform: translate3d(0px, 0, 0); + -ms-transition-timing-function: ease; + -webkit-transition-property: -webkit-transform, left, top; + -moz-transition-property: -moz-transform, left, top; + -o-transition-property: -o-transform, left, top; + -ms-transition-property: -ms-transform, left, top; + transition-property: transform, left, top; + -webkit-transition-duration: 0s; + -moz-transition-duration: 0s; + -o-transition-duration: 0s; + -ms-transition-duration: 0s; + transition-duration: 0s; + -webkit-transform: translate3d(0px, 0, 0); + -moz-transform: translate3d(0px, 0, 0); + -o-transform: translate3d(0px, 0, 0); + -ms-transform: translate3d(0px, 0, 0); + transform: translate3d(0px, 0, 0); + -webkit-transition-timing-function: ease; + -moz-transition-timing-function: ease; + -o-transition-timing-function: ease; + -ms-transition-timing-function: ease; + transition-timing-function: ease; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.swiperslide { + font-size: 15px; font-size: 1rem; - line-height: 1; - background-position: top center; + float: left; +} +.swiperwp8horizontal { + -ms-touch-action: pan-y; +} +.swiperwp8vertical { + -ms-touch-action: pan-x; +} +.countdown { + font-size: 15px; + font-size: 1rem; +} +.countdown_pane { + border: 0.266666666666667em solid #fff; + background: #008fcc; + color: #fff; + text-align: center; + display: inline-block; + margin: 0.333333333333333em; + padding: 0.666666666666667em; + -webkit-border-radius: 0.666666666666667em; + border-radius: 0.666666666666667em; + width: 4.666666666666667em; + height: 4.666666666666667em; + text-shadow: none; + -webkit-box-shadow: 0 0 18px rgba(0,0,0,0.13), 0 2px 6px rgba(0,0,0,0.25); + box-shadow: 0 0 18px rgba(0,0,0,0.13), 0 2px 6px rgba(0,0,0,0.25); +} +.countdown_pane_count { + font-weight: bold; + font-size: 2em; + line-height: 0.866666666666667em; +} +.countdown_pane_unit { + font-size: 1.2em; +} +.stageteaser { + font-size: 15px; + font-size: 1rem; + position: relative; + width: 100%; +} +.stageteaser_background { + height: 38.666666666666664em; + overflow: hidden; +} +.stageteaser_background_image { + display: block; + background-position: center center; background-repeat: no-repeat; -webkit-background-size: cover; -moz-background-size: cover; background-size: cover; - height: 36.25em; - position: relative; + height: 100%; + position: absolute; + left: 0; + right: 0; + -webkit-transition: margin 1s ease; + -moz-transition: margin 1s ease; + -o-transition: margin 1s ease; + -ms-transition: margin 1s ease; + transition: margin 1s ease; } -.stage_header { - padding: 4.875em; +.stageteaser_content { + height: 38.666666666666664em; + margin-top: -38.666666666666664em; +} +.stageteaser_content_header { + position: absolute; + width: 100%; + padding: 5.2em; + line-height: 0.9; text-shadow: 0 0 18px rgba(0,0,0,0.13), 0 2px 6px rgba(0,0,0,0.25); text-align: center; + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transition: opacity 1s ease; + -moz-transition: opacity 1s ease; + -o-transition: opacity 1s ease; + -ms-transition: opacity 1s ease; + transition: opacity 1s ease; } -.stage_header_subtitle { - font-size: 1.875em; +.stageteaser_content_headerhidden { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: literal("alpha(opacity=0)"); +} +.stageteaser_content_header_subtitle { + font-size: 2em; font-weight: 400; color: #fff; - margin: 0; + margin: 0 0 0.533333333333333em; } -.stage_header_title { - font-size: 4.5em; +.stageteaser_content_header_title { + font-size: 4.8em; font-weight: 700; color: #fff; margin: 0; } -.stage_header_message { - font-size: 1.875em; - font-weight: 600; - color: #fff; - margin: 0; +.stageteaser_content_header_countdown { + font-size: 15px; + font-size: 1rem; } -.stage_band { +.stageteaser_content_band { position: absolute; bottom: 0; - right: 0; left: 0; + right: 0; background-color: rgba(51,51,51,0.6); - text-align: center; - padding: 1.5625em; + padding: 1.4em 1.666666666666667em; } -.stage_band_message { +.stageteaser_content_band_item { + padding: 0 2em; +} +.stageteaser_content_band[data-bandcount="2"] .stageteaser_content_band_item { + width: 50%; + float: left; +} +.stageteaser_content_band[data-bandcount="2"] .stageteaser_content_band_item:first-child { + border-right: solid 1px #82868b; +} +.stageteaser_content_band_text { display: inline-block; +} +.stageteaser_content_band_text_headline { color: #f0ab00; - font-size: 1.5em; + font-size: 1.2em; font-weight: 700; - text-shadow: 0 0 0.625em rgba(51,51,51,0.45); + text-shadow: 0 0 0.666666666666667em rgba(51,51,51,0.45); text-transform: uppercase; + margin: 0.466666666666667em 0 0.2em; } -.stage_band_name { - display: inline-block; +.stageteaser_content_band_text_name { color: #fff; - font-size: 1.5em; - text-shadow: 0 0 0.625em rgba(51,51,51,0.45); + font-size: 1.066666666666667em; + text-shadow: 0 0 0.666666666666667em rgba(51,51,51,0.45); } -.stage_band_action { - font-size: 1.125em; - padding: 0.875em 1.875em; - margin-left: 1.25em; - text-transform: none; +.stageteaser_content_band_action { + float: right; + font-size: 1.2em; + padding: 0.4em 0.933333333333333em; + margin: 0.7em 0 0.5em; +} +.stageteaser_content_band_item[data-bandcount="1"] { + text-align: center; + padding: 0.7em 0.7em 0.55em; +} +.stageteaser_content_band_item[data-bandcount="1"] .stageteaser_content_band_text { + font-size: 18px; + font-size: 1.2rem; +} +.stageteaser_content_band_item[data-bandcount="1"] .stageteaser_content_band_text_headline { + display: inline-block; + margin: 5px 0 0; +} +.stageteaser_content_band_item[data-bandcount="1"] .stageteaser_content_band_text_headline:after { + content: "–"; + margin: 0 0.333333333333333em 0 0.666666666666667em; +} +.stageteaser_content_band_item[data-bandcount="1"] .stageteaser_content_band_text_name { + display: inline-block; +} +.stageteaser_content_band_item[data-bandcount="1"] .stageteaser_content_band_action { + float: none; + margin: 0 0 0 1em; +} +.stage { + font-size: 15px; + font-size: 1rem; + height: 38.666666666666664em; + position: relative; + clear: both; +} +.stage_teasers { + height: 38.666666666666664em; + width: 100%; +} +.stage_controls { + font-size: 15px; + font-size: 1rem; +} +.stage_progress { + height: 0.333333333333333em; + margin-top: -0.333333333333333em; + z-index: 10; + position: relative; +} +.stage_progress_bar { + background-color: #f0ab00; + height: 0.333333333333333em; + width: 0%; + -webkit-transition: width 0.1s linear; + -moz-transition: width 0.1s linear; + -o-transition: width 0.1s linear; + -ms-transition: width 0.1s linear; + transition: width 0.1s linear; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.java index 4cbc1f9b66b..e4e873efe35 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.java @@ -1,45 +1,88 @@ package com.sap.sailing.gwt.home.client.shared.stage; +import java.util.ArrayList; +import java.util.List; + import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.home.client.shared.EventDatesFormatterUtil; +import com.sap.sailing.gwt.home.client.app.PlaceNavigator; +import com.sap.sailing.gwt.idangerous.Swiper; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sse.common.Util.Pair; public class Stage extends Composite { - - @SuppressWarnings("unused") - private EventDTO featuredEvent; - @UiField Label subtitle; - @UiField Label title; - @UiField Label message; - @UiField SpanElement regattaState; - @UiField SpanElement actionMessage; + @SuppressWarnings("unused") + private List> featuredEvents; + private List stageTeaserComposites; + + @UiField HTMLPanel stageElementsPanel; + @UiField Anchor nextStageTeaserLink; + @UiField Anchor prevStageTeaserLink; + + private StageTeaser stageTeaser; + + private Swiper swiper; + + private final PlaceNavigator placeNavigator; + interface StageUiBinder extends UiBinder { } private static StageUiBinder uiBinder = GWT.create(StageUiBinder.class); - public Stage() { + public Stage(PlaceNavigator placeNavigator) { + this.placeNavigator = placeNavigator; + StageResources.INSTANCE.css().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); - } - - public void setFeaturedEvent(EventDTO featuredEvent) { - this.featuredEvent = featuredEvent; - title.setText(featuredEvent.getName()); - subtitle.setText(featuredEvent.venue.getName()); - - message.setText(EventDatesFormatterUtil.formatDateRangeWithYear(featuredEvent.startDate, featuredEvent.endDate)); - actionMessage.setInnerText("[Race 6]"); - regattaState.setInnerText("Next Race"); + stageTeaserComposites = new ArrayList(); } + public void setFeaturedEvents(List> featuredEvents) { + this.featuredEvents = featuredEvents; + + for(Pair typeAndEvent: featuredEvents) { + switch (typeAndEvent.getA()) { + case POPULAR: + stageTeaser = new PopularEventStageTeaser(typeAndEvent.getB(), placeNavigator); + break; + case RUNNING: + stageTeaser = new LiveEventStageTeaser(typeAndEvent.getB(), placeNavigator); + break; + case UPCOMING_SOON: + stageTeaser = new UpcomingEventStageTeaser(typeAndEvent.getB(), placeNavigator); + break; + } + stageElementsPanel.add(stageTeaser); + stageTeaserComposites.add(stageTeaser); + } + + this.swiper = Swiper.createWithDefaultOptions(StageResources.INSTANCE.css().stage_teasers(), + StageResources.INSTANCE.css().swiperwrapper(), + StageResources.INSTANCE.css().swiperslide()); + } + + @UiHandler("nextStageTeaserLink") + public void nextStageTeaserLinkClicked(ClickEvent e) { + if (this.swiper != null) { + this.swiper.swipeNext(); + } + } + + @UiHandler("prevStageTeaserLink") + public void prevStageTeaserLinkClicked(ClickEvent e) { + if (this.swiper != null) { + this.swiper.swipePrev(); + } + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.ui.xml index 93d3b5c29a0..c3c299ca3f7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/Stage.ui.xml @@ -3,27 +3,19 @@ xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:s="urn:import:com.sap.sailing.gwt.home.client.shared"> + -
-
-

-

-
-
-
-
-
-
 - -
-
- -
-
-
-
+
+
+ +
+
+
+
+ + +
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageEventType.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageEventType.java new file mode 100644 index 00000000000..cd74414e927 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageEventType.java @@ -0,0 +1,5 @@ +package com.sap.sailing.gwt.home.client.shared.stage; + +public enum StageEventType { + RUNNING, UPCOMING_SOON, POPULAR +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageResources.java index 749273fd8cb..af01e834515 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageResources.java @@ -11,14 +11,34 @@ public interface StageResources extends ClientBundle { LocalCss css(); public interface LocalCss extends CssResource { + String countdown(); + String countdown_pane(); + String countdown_pane_count(); + String countdown_pane_unit(); + String stageteaser(); + String stageteaser_background(); + String stageteaser_background_image(); + String stageteaser_content(); + String stageteaser_content_header(); + String stageteaser_content_headerhidden(); + String stageteaser_content_header_subtitle(); + String stageteaser_content_header_title(); + String stageteaser_content_header_countdown(); + String stageteaser_content_band(); + String stageteaser_content_band_item(); + String stageteaser_content_band_text(); + String stageteaser_content_band_text_headline(); + String stageteaser_content_band_text_name(); + String stageteaser_content_band_action(); + String swipercontainer(); + String swiperwrapper(); + String swiperslide(); + String swiperwp8horizontal(); + String swiperwp8vertical(); String stage(); - String stage_header(); - String stage_header_subtitle(); - String stage_header_title(); - String stage_header_message(); - String stage_band(); - String stage_band_message(); - String stage_band_name(); - String stage_band_action(); + String stage_teasers(); + String stage_controls(); + String stage_progress(); + String stage_progress_bar(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.java new file mode 100644 index 00000000000..97776f87fc1 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.java @@ -0,0 +1,37 @@ +package com.sap.sailing.gwt.home.client.shared.stage; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTMLPanel; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.shared.EventDTO; + +public abstract class StageTeaser extends Composite { + @UiField DivElement bandCount; + @UiField SpanElement subtitle; + @UiField SpanElement title; + @UiField DivElement countDown; + @UiField HTMLPanel stageTeaserBandsPanel; + @UiField DivElement teaserImage; + + private final static String DEFAULT_STAGE_IMAGE_URL = "http://static.sapsailing.com/ubilabsimages/default/default_stage_event_teaser.jpg"; + + interface StageTeaserUiBinder extends UiBinder { + } + + private static StageTeaserUiBinder uiBinder = GWT.create(StageTeaserUiBinder.class); + + public StageTeaser(EventDTO event) { + StageResources.INSTANCE.css().ensureInjected(); + initWidget(uiBinder.createAndBindUi(this)); + + String stageImageUrl = event.getStageImageURL() != null ? event.getStageImageURL() : DEFAULT_STAGE_IMAGE_URL; + + String backgroundImage = "url(" + stageImageUrl + ")"; + teaserImage.getStyle().setBackgroundImage(backgroundImage); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.ui.xml new file mode 100644 index 00000000000..3f4d546d56b --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaser.ui.xml @@ -0,0 +1,38 @@ + + + + + + + +
+
+
+
+
+

+ +

+

+ +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaserBand.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaserBand.java new file mode 100644 index 00000000000..b535afb6a24 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaserBand.java @@ -0,0 +1,47 @@ +package com.sap.sailing.gwt.home.client.shared.stage; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Anchor; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.home.client.app.PlaceNavigator; +import com.sap.sailing.gwt.home.client.shared.EventDatesFormatterUtil; +import com.sap.sailing.gwt.ui.shared.EventDTO; + +public class StageTeaserBand extends Composite { + + interface StageTeaserBandUiBinder extends UiBinder { + } + + private static StageTeaserBandUiBinder uiBinder = GWT.create(StageTeaserBandUiBinder.class); + + @UiField SpanElement bandTitle; + @UiField SpanElement bandSubtitle; + @UiField Anchor actionLink; + + private final PlaceNavigator placeNavigator; + private final EventDTO event; + + public StageTeaserBand(EventDTO event, PlaceNavigator placeNavigator) { + this.event = event; + this.placeNavigator = placeNavigator; + + StageResources.INSTANCE.css().ensureInjected(); + initWidget(uiBinder.createAndBindUi(this)); + + bandTitle.setInnerText(event.getName()); + bandSubtitle.setInnerText(EventDatesFormatterUtil.formatDateRangeWithYear(event.startDate, event.endDate)); + + actionLink.setText("Show event"); + } + + @UiHandler("actionLink") + public void actionLinkClicked(ClickEvent e) { + placeNavigator.goToEvent(event.id.toString(), event.getBaseURL()); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaserBand.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaserBand.ui.xml new file mode 100644 index 00000000000..ad7fb44b52a --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/StageTeaserBand.ui.xml @@ -0,0 +1,19 @@ + + + + + + + +
+
+
+
+
+ +
+ +
+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/UpcomingEventStageTeaser.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/UpcomingEventStageTeaser.java new file mode 100644 index 00000000000..ebe38edcfcc --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/shared/stage/UpcomingEventStageTeaser.java @@ -0,0 +1,24 @@ +package com.sap.sailing.gwt.home.client.shared.stage; + +import com.sap.sailing.gwt.home.client.app.PlaceNavigator; +import com.sap.sailing.gwt.ui.shared.EventDTO; + +public class UpcomingEventStageTeaser extends StageTeaser { + + public UpcomingEventStageTeaser(EventDTO event, PlaceNavigator placeNavigator) { + super(event); + + title.setInnerText(event.getName()); + subtitle.setInnerText(event.venue.getName()); + + countDown.setAttribute("data-starttime", event.startDate.toString()); + countDown.setAttribute("data-days", ""); + countDown.setAttribute("data-hours", ""); + countDown.setAttribute("data-minutes", ""); + countDown.setAttribute("data-seconds", ""); + + bandCount.setAttribute("data-bandcount", "1"); + stageTeaserBandsPanel.add(new StageTeaserBand(event, placeNavigator)); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/idangerous/Swiper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/idangerous/Swiper.java new file mode 100644 index 00000000000..ec70192040d --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/idangerous/Swiper.java @@ -0,0 +1,30 @@ +package com.sap.sailing.gwt.idangerous; + +import com.google.gwt.core.client.JavaScriptObject; + +/** + * Wrapping http://www.idangero.us/sliders/swiper/ + * + */ +public final class Swiper extends JavaScriptObject { + + protected Swiper() {}; + + public static native Swiper createWithDefaultOptions(String containerClass, String wrapperClass, String slideClass) /*-{ + var options = { + loop: true, + wrapperClass: wrapperClass, + slideClass: slideClass + }; + return new $wnd.Swiper('.'+containerClass, options); + }-*/; + + public native void swipeNext() /*-{ + this.swipeNext(); + }-*/; + + public native void swipePrev() /*-{ + this.swipePrev(); + }-*/; + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 9806f8fc1ab..a3448849ae4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -97,6 +97,8 @@ public interface SailingService extends RemoteService { List getRegattas(); + RegattaDTO getRegattaByName(String regattaName); + List getEvents() throws Exception; List getPublicEventsOfAllSailingServers() throws Exception; @@ -517,5 +519,5 @@ public interface SailingService extends RemoteService { /** * @return The RaceDTO of the modified race or null, if the given newStartTimeReceived was null. */ - RaceDTO setStartTimeReceivedForRace(RaceIdentifier raceIdentifier, Date newStartTimeReceived); + RaceDTO setStartTimeReceivedForRace(RaceIdentifier raceIdentifier, Date newStartTimeReceived); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index d873b924eaf..7a4c5a95b0b 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -84,6 +84,9 @@ public interface SailingServiceAsync { void getRegattas(AsyncCallback> callback); + void getRegattaByName(String regattaName, AsyncCallback asyncCallback); + + /** * The string returned in the callback's pair is the common event name * @param listHiddenRaces @@ -479,7 +482,7 @@ public interface SailingServiceAsync { void getBuildVersion(AsyncCallback callback); void stopReplicatingFromMaster(AsyncCallback asyncCallback); - + void getRegattaStructureForEvent(UUID eventId, AsyncCallback> asyncCallback); void getRaceStateEntriesForRaceGroup(UUID eventId, List visibleCourseAreas, diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSelector.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSelector.java index 869f12db900..5c46c79d550 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSelector.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSelector.java @@ -47,6 +47,12 @@ import com.sap.sse.gwt.client.player.Timer; import com.sap.sse.gwt.client.player.Timer.PlayModes; import com.sap.sse.gwt.client.player.Timer.PlayStates; +/** + * The media selector is used as an {@link AsyncCallback} that receives a collection of {@link MediaTrack}s in case the + * call was successful. This could, e.g., be a call to + * {@link MediaServiceAsync#getMediaTracksForRace(RegattaAndRaceIdentifier, AsyncCallback)}. When the call returns the + * track collection, the UI is updated accordingly. + */ public class MediaSelector implements PlayStateListener, TimeListener, AsyncCallback>, MediaSelectionListener, CloseHandler, ClosingHandler { @@ -82,7 +88,7 @@ public class MediaSelector implements PlayStateListener, TimeListener, this.stringMessages = stringMessages; this.errorReporter = errorReporter; this.user = user; - this.autoSelectMedia = autoSelectMedia; + this.autoSelectMedia = autoSelectMedia; Window.addCloseHandler(this); Window.addWindowClosingHandler(this); @@ -91,7 +97,6 @@ public class MediaSelector implements PlayStateListener, TimeListener, manageMediaButton = new Button(); manageMediaButton.addClickHandler(new ClickHandler() { - @Override public void onClick(ClickEvent event) { if (mediaSelectionDialog.isShowing()) { @@ -288,7 +293,7 @@ public class MediaSelector implements PlayStateListener, TimeListener, toggleMediaButton.setValue(autoSelectMedia); if (autoSelectMedia) { - playDefault(); + playDefault(); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java index e5d78c36b54..c5215f64f34 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java @@ -782,6 +782,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe return LatLng.newInstance(lat2 / Math.PI * 180., lon2 / Math.PI * 180.); } + /** + * Returns a pair whose first component is the leg number (one-based) of the competitor returned as the second component. + */ private com.sap.sse.common.Util.Pair getLeadingVisibleCompetitorInfo(Iterable competitorsToShow) { CompetitorDTO leadingCompetitorDTO = null; int legOfLeaderCompetitor = -1; @@ -789,7 +792,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe for (QuickRankDTO quickRank : quickRanks) { if (Util.contains(competitorsToShow, quickRank.competitor)) { leadingCompetitorDTO = quickRank.competitor; - legOfLeaderCompetitor = quickRank.legNumber; + legOfLeaderCompetitor = quickRank.legNumberOneBased; return new com.sap.sse.common.Util.Pair(legOfLeaderCompetitor, leadingCompetitorDTO); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java index c619c0f9a16..3da1342b473 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java @@ -271,9 +271,15 @@ public class RaceBoardPanel extends SimplePanel implements RegattasDisplayer, Ra return filterSets; } + /** + * Adds the media selector drop down and fills it with media for the current race. + * NOTE: + * Media selector will NOT listen and react to changes of the start time during a race board session. + * This case and its consequences are considered negligible. + * Consequently, media selector will also NOT react on media added newly during a race board session. + */ private void addMediaSelectorToNavigationMenu() { MediaSelector mediaSelector = new MediaSelector(selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, stringMessages, errorReporter, this.user, getConfiguration().isAutoSelectMedia()); -// raceTimesInfoProvider.addRaceTimesInfoProviderListener(mediaSelector); timer.addPlayStateListener(mediaSelector); timer.addTimeListener(mediaSelector); mediaService.getMediaTracksForRace(selectedRaceIdentifier, mediaSelector); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 9d1b91b3a7e..dcaf291917d 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -736,7 +736,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public List getRegattas() throws IllegalArgumentException { + public List getRegattas() { List result = new ArrayList(); for (Regatta regatta : getService().getAllRegattas()) { result.add(convertToRegattaDTO(regatta)); @@ -744,6 +744,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S return result; } + @Override + public RegattaDTO getRegattaByName(String regattaName) { + RegattaDTO result = null; + if (regattaName != null && !regattaName.isEmpty()) { + Regatta regatta = getService().getRegatta(new RegattaName(regattaName)); + if (regatta != null) { + result = convertToRegattaDTO(regatta); + } + } + return result; + } + private MarkDTO convertToMarkDTO(Mark mark, Position position) { MarkDTO markDTO; if(position != null) { @@ -1865,8 +1877,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S for (Competitor competitor : trackedRace.getCompetitorsFromBestToWorst(dateAsTimePoint)) { TrackedLegOfCompetitor trackedLeg = trackedRace.getTrackedLeg(competitor, dateAsTimePoint); if (trackedLeg != null) { - int legNumber = race.getCourse().getLegs().indexOf(trackedLeg.getLeg()) + 1; - QuickRankDTO quickRankDTO = new QuickRankDTO(baseDomainFactory.convertToCompetitorDTO(competitor), rank, legNumber); + int legNumberOneBased = race.getCourse().getLegs().indexOf(trackedLeg.getLeg()) + 1; + QuickRankDTO quickRankDTO = new QuickRankDTO(baseDomainFactory.convertToCompetitorDTO(competitor), rank, legNumberOneBased); result.add(quickRankDTO); } rank++; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java index b86d2cf1c33..6d9910d3847 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java @@ -35,7 +35,7 @@ public class CompactRaceMapDataDTO implements IsSerializable { } this.quickRanks = new ArrayList(quickRanks.size()); for (QuickRankDTO quickRank : quickRanks) { - this.quickRanks.add(new CompactQuickRankDTO(quickRank.competitor.getIdAsString(), quickRank.rank, quickRank.legNumber)); + this.quickRanks.add(new CompactQuickRankDTO(quickRank.competitor.getIdAsString(), quickRank.rank, quickRank.legNumberOneBased)); } this.courseSidelines = courseSidelines; this.coursePositions = coursePositions; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java index 5fc80786ef8..6224884280c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java @@ -97,6 +97,27 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable { return imageURLs; } + public String getStageImageURL() { + String result = null; + for(String imageUrl: imageURLs) { + if(imageUrl.contains("stage") || imageUrl.contains("STAGE")) { + result = imageUrl; + break; + } + } + return result; + } + + public List getPhotoGalleryImageURLs() { + List result = new ArrayList(); + for(String imageUrl: imageURLs) { + if(!imageUrl.contains("stage") && !imageUrl.contains("STAGE")) { + result.add(imageUrl); + } + } + return result; + } + public List getVideoURLs() { return videoURLs; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventDTO.java index 5bbdc1dd04c..f2d41860557 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventDTO.java @@ -45,7 +45,7 @@ public class EventDTO extends EventBaseDTO { leaderboardGroups.add(leaderboardGroup); } - public Iterable getLeaderboardGroups() { + public List getLeaderboardGroups() { return leaderboardGroups; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/QuickRankDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/QuickRankDTO.java index 4ec033960ad..c7e83f01a61 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/QuickRankDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/QuickRankDTO.java @@ -6,13 +6,17 @@ import com.sap.sailing.domain.common.dto.CompetitorDTO; public class QuickRankDTO implements IsSerializable { public CompetitorDTO competitor; public int rank; - public int legNumber; + + /** + * The {@link #competitor}'s leg number, starting with 1 for the first leg + */ + public int legNumberOneBased; public QuickRankDTO() {} - public QuickRankDTO(CompetitorDTO competitorDTO, int rank, int legNumber) { + public QuickRankDTO(CompetitorDTO competitorDTO, int rank, int legNumberOneBased) { this.competitor = competitorDTO; this.rank = rank; - this.legNumber = legNumber; + this.legNumberOneBased = legNumberOneBased; } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/Home.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/Home.gwt.xml index c29cd5c3947..8dd534000e0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/Home.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/Home.gwt.xml @@ -74,4 +74,5 @@ + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.css b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.css index 8f4b3b06eb5..eff5c0be943 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.css +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/main.css @@ -238,3 +238,101 @@ figcaption { .mainsection_navigation { text-align: center; } + +.lightbox { + font-size: 16px; + font-size: 1rem; +} +.lightbox_overlay { + font-size: 16px; + font-size: 1rem; + background: #000; + opacity: 0.7; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; + filter: literal("alpha(opacity=70)"); + width: 100%; + height: 100%; + position: fixed; + left: 0; + top: 0; + z-index: 2000; + -webkit-transition: opacity 0.3s ease; + -moz-transition: opacity 0.3s ease; + -o-transition: opacity 0.3s ease; + -ms-transition: opacity 0.3s ease; + transition: opacity 0.3s ease; +} +.lightbox_overlayhidden { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.lightbox_content { + position: fixed; + width: 100%; + height: 100%; + opacity: 1; + -ms-filter: none; + filter: none; + top: 0; + left: 0; + z-index: 2001; + background-repeat: no-repeat; + background-position: center center; + -webkit-transition: opacity 0.3s ease; + -moz-transition: opacity 0.3s ease; + -o-transition: opacity 0.3s ease; + -ms-transition: opacity 0.3s ease; + transition: opacity 0.3s ease; +} +.lightbox_contenthidden { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.lightbox_content_enlargedimage { + -webkit-transition: margin 0.7s linear; + -moz-transition: margin 0.7s linear; + -o-transition: margin 0.7s linear; + -ms-transition: margin 0.7s linear; + transition: margin 0.7s linear; + display: inline-block; + position: absolute; + left: 50%; + top: 50%; +} +.lightbox_content_enlargedimage_caption { + text-align: center; + color: #f6f9fc; + font-weight: 700; +} +.lightbox_content_enlargedimage_close { + display: inline-block; + background-image: url("images/home/x_lightbox.png"); + background-repeat: no-repeat; + background-position: center center; + width: 1.25em; + height: 0; + overflow: hidden; + padding-top: 1.25em; + position: absolute; + top: 1.25em; + right: 1.25em; + cursor: pointer; + z-index: 2003; +} +/** +.lightbox_content .media_slideshow_controls { + z-index: 2002; +} +*/ + +.lightbox_data { + display: none; +} +.lightbox_photo { + cursor: pointer; +} + +.lightbox_item { +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/MediaLibrary.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/MediaLibrary.java index d244702e18a..854ba105c03 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/MediaLibrary.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/MediaLibrary.java @@ -15,12 +15,11 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; import com.sap.sailing.domain.common.media.MediaTrack; import com.sap.sailing.domain.common.media.MediaUtil; +import com.sap.sailing.util.impl.LockUtil; +import com.sap.sailing.util.impl.NamedReentrantReadWriteLock; class MediaLibrary { @@ -68,9 +67,7 @@ class MediaLibrary { */ private final ConcurrentMap> cacheByInterval = new ConcurrentHashMap>(); - private final ReadWriteLock lock = new ReentrantReadWriteLock(); - private final Lock readLock = lock.readLock(); - private final Lock writeLock = lock.writeLock(); + private final NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock(MediaLibrary.class.getName(), /* fair */ false); // /** // * Sort in reverse order of start time! For equal start times compare dbId to distinguish different instances. @@ -94,7 +91,7 @@ class MediaLibrary { * performance gain. * * Actually, efficient lookup of overlapping intervals is supposed to be performed using an interval tree, e.g. - * http://thekevindolan.com/2010/02/interval-tree/ + * http://en.wikipedia.org/wiki/Interval_tree. * * However, considering the expected low number of media entries and the expected high rate of cache hits doesn't * justify providing a dedicated interval tree implementation (given that there's none readily available). @@ -112,7 +109,7 @@ class MediaLibrary { if (startTime != null) { Interval interval = new Interval(startTime, endTime); - readLock.lock(); + LockUtil.lockForRead(lock); try { Set cachedMediaTracks = cacheByInterval.get(interval); if (cachedMediaTracks == null) { @@ -134,7 +131,7 @@ class MediaLibrary { } } finally { - readLock.unlock(); + LockUtil.unlockAfterRead(lock); } } // else @@ -152,65 +149,65 @@ class MediaLibrary { } void addMediaTracks(Collection mediaTracks) { - writeLock.lock(); + LockUtil.lockForWrite(lock); try { for (MediaTrack mediaTrack : mediaTracks) { this.mediaTracksByDbId.put(mediaTrack, mediaTrack); updateCache_Add(mediaTrack); } } finally { - writeLock.unlock(); + LockUtil.unlockAfterWrite(lock); } } void deleteMediaTrack(MediaTrack mediaTrack) { - writeLock.lock(); + LockUtil.lockForWrite(lock); try { MediaTrack deletedMediaTrack = mediaTracksByDbId.remove(mediaTrack); updateCache_Remove(deletedMediaTrack); } finally { - writeLock.unlock(); + LockUtil.unlockAfterWrite(lock); } } void titleChanged(MediaTrack changedMediaTrack) { - writeLock.lock(); + LockUtil.lockForWrite(lock); try { MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack); if (mediaTrack != null) { mediaTrack.title = changedMediaTrack.title; } } finally { - writeLock.unlock(); + LockUtil.unlockAfterWrite(lock); } } void urlChanged(MediaTrack changedMediaTrack) { - writeLock.lock(); + LockUtil.lockForWrite(lock); try { MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack); if (mediaTrack != null) { mediaTrack.url = changedMediaTrack.url; } } finally { - writeLock.unlock(); + LockUtil.unlockAfterWrite(lock); } } void mimeTypeChanged(MediaTrack changedMediaTrack) { - writeLock.lock(); + LockUtil.lockForWrite(lock); try { MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack); if (mediaTrack != null) { mediaTrack.mimeType = changedMediaTrack.mimeType; } } finally { - writeLock.unlock(); + LockUtil.unlockAfterWrite(lock); } } void startTimeChanged(MediaTrack changedMediaTrack) { - writeLock.lock(); + LockUtil.lockForWrite(lock); try { MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack); if (mediaTrack != null) { @@ -218,12 +215,12 @@ class MediaLibrary { updateCache_Change(mediaTrack); } } finally { - writeLock.unlock(); + LockUtil.unlockAfterWrite(lock); } } void durationChanged(MediaTrack changedMediaTrack) { - writeLock.lock(); + LockUtil.lockForWrite(lock); try { MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack); if (mediaTrack != null) { @@ -231,7 +228,7 @@ class MediaLibrary { updateCache_Change(mediaTrack); } } finally { - writeLock.unlock(); + LockUtil.unlockAfterWrite(lock); } } @@ -273,20 +270,20 @@ class MediaLibrary { * Returns a non-live copy of the media tracks */ Collection allTracks() { - readLock.lock(); + LockUtil.lockForRead(lock); try { return new ArrayList(mediaTracksByDbId.values()); } finally { - readLock.unlock(); + LockUtil.unlockAfterRead(lock); } } void serialize(ObjectOutputStream stream) throws IOException { - readLock.lock(); + LockUtil.lockForRead(lock); try { stream.writeObject(new ArrayList(mediaTracksByDbId.values())); } finally { - readLock.unlock(); + LockUtil.unlockAfterRead(lock); } } @@ -296,12 +293,12 @@ class MediaLibrary { } public void clear() { - writeLock.lock(); + LockUtil.lockForWrite(lock); try { mediaTracksByDbId.clear(); cacheByInterval.clear(); } finally { - writeLock.unlock(); + LockUtil.unlockAfterWrite(lock); } }