Index: umc/js/appcenter/Carousel.js =================================================================== --- umc/js/appcenter/Carousel.js (Revision 67064) +++ umc/js/appcenter/Carousel.js (Arbeitskopie) @@ -57,6 +57,9 @@ itemHeight: null, heighestImg: null, + heighestImgRatio: null, + _youtubeIframeRatio: null, + onlyYoutubeVideos: null, // items: Array // array of objects({src: }) @@ -66,7 +69,7 @@ allItemsLoaded: null, - bigThumbnails: null, + isBigThumbnails: null, _resizeDeferred: null, @@ -76,30 +79,19 @@ this.contentSliderOffset = 0; this.shownItemIndex = 0; this.allItemsLoaded = false; - this.bigThumbnails = false; + this.isBigThumbnails = false; + this._youtubeIframeRatio = 16 / 9; + this.heighestImgRatio = this._youtubeIframeRatio; + this.heighestImg = this.heighestImg || {w: 1600, h: 900}; + this.onlyYoutubeVideos = true; + this.defaultSliderWidth = 0; }, - buildRendering: function() { - this.inherited(arguments); + postCreate: function() { + this._setDefaultThumbsHeight(); - this.outerContainer = new ContainerWidget({ - 'class': 'carouselOuterContainer' - }); - - this.addChild(this.outerContainer); - this.own(this.outerContainer); - - this.renderContentSlider(); - this.renderNavButtons(); - this.renderScaleButton(); - - }, - - postCreate: function() { if (window.YT && window.YT.loaded) { - setTimeout(lang.hitch(this, function() { - this._renderYoutubeVideos(); - }), 500); + //stub } else { //load youtube api var tag = document.createElement('script'); @@ -115,25 +107,78 @@ }); } onPlayerReady = lang.hitch(this, function() { - this.imagesLoaded(); + this.thumbLoaded(); }); + onPlayerError = lang.hitch(this, function() { + this.thumbLoaded(); + }); }, - renderContentSlider: function() { + buildRendering: function() { + this.inherited(arguments); + + this.outerContainer = new ContainerWidget({ + 'class': 'carouselOuterContainer', + style: { + 'height': this.itemHeight + 'px' + } + }); this.contentSliderWrapper = new ContainerWidget({ 'class': 'contentSliderWrapper' }); + + this.outerContainer.addChild(this.contentSliderWrapper); + this.addChild(this.outerContainer); + this.own(this.outerContainer); + + this.renderNavButtons(); + this.renderScaleButton(); + this.renderContentSlider(); + + }, + + renderNavButtons: function() { + this.leftButton = domConstruct.create('div', { + 'class': 'carouselButton leftCarouselButton', + onclick: lang.hitch(this, function() { + this.showItem(this.shownItemIndex - 1); + }) + }, this.contentSliderWrapper.domNode, 'before'); + domConstruct.create('div', { + 'class': 'carouselButtonImage' + }, this.leftButton); + + this.rightButton = domConstruct.create('div', { + 'class': 'carouselButton rightCarouselButton', + onclick: lang.hitch(this, function() { + this.showItem(this.shownItemIndex + 1); + }) + }, this.contentSliderWrapper.domNode, 'after'); + domConstruct.create('div', { + 'class': 'carouselButtonImage' + }, this.rightButton); + }, + + renderScaleButton: function() { + this.scaleButton = domConstruct.create('div', { + 'class': 'scaleButton dijitHidden', + onclick: lang.hitch(this, function() { + this.togglePreviewSize(this.shownItemIndex); + }) + }, this.domNode); + }, + + renderContentSlider: function() { this.contentSlider = new ContainerWidget({ 'class': 'contentSlider' }); this.contentSliderWrapper.addChild(this.contentSlider); - this.outerContainer.addChild(this.contentSliderWrapper); this._renderThumbs(); }, _renderThumbs: function() { - this.loadedImagesCount = 0; + this.loadedThumbsCount = 0; var index = 0; var uniqueYTVideoIds = []; @@ -145,27 +190,51 @@ } uniqueYTVideoIds.push(videoId); - var videoWrapper = domConstruct.create('div', {'class': 'galleryVideo'}, this.contentSlider.domNode); - var div = domConstruct.create('div', { + var videoWrapper = domConstruct.create('div', { + 'class': 'galleryThumbWrapper galleryVideoWrapper' + }, this.contentSlider.domNode); + + var galleryVideo = domConstruct.create('div', { + 'class': 'galleryThumb galleryVideo notLoadedBackground', + style: { + 'width': this.itemHeight * this._youtubeIframeRatio + 'px' + }, id: videoId }, videoWrapper); this.itemNodes.push(videoWrapper); + + if (window.YT && window.YT.loaded) { + setTimeout(lang.hitch(this, function() { + this._renderYoutubeVideo(galleryVideo); + }), 0); + } } else { - var imgWrapper = domConstruct.create('div', {}, this.contentSlider.domNode); + var imgWrapper = domConstruct.create('div', { + 'class': 'galleryThumbWrapper galleryImgWrapper' + }, this.contentSlider.domNode); + var img = domConstruct.create('img', { src: item.src, index: index, - 'class': 'carouselScreenshot', + 'class': 'galleryThumb galleryImg', onload: lang.hitch(this, function() { this._updateHeighestImage(img); - this.imagesLoaded(); + this.resizeCarousel(); + this.thumbLoaded(); }), + onerror: lang.hitch(this, function() { + domClass.add(img.parentNode, 'brokenImg'); + this.resizeCarousel(); + this.thumbLoaded(); + }), onclick: lang.hitch(this, function(evt) { this.togglePreviewSize(parseInt(evt.target.getAttribute('index'))); }) }, imgWrapper); this.itemNodes.push(imgWrapper); + + this.onlyYoutubeVideos = false; } index++; })); @@ -172,21 +241,35 @@ }, _renderYoutubeVideos: function() { - query('.galleryVideo', this.contentSlider.domNode).forEach(lang.hitch(this, function(videoWrapper) { - var player; - var videoId = videoWrapper.firstChild.id; - player = new YT.Player(videoId, { - height: this.itemHeight.toString(), - width: 'auto', - videoId: videoId, - events: { - 'onReady': onPlayerReady - } - }); - this.own(player); + query('.galleryVideo', this.contentSlider.domNode).forEach(lang.hitch(this, function(galleryVideo) { + this._renderYoutubeVideo(galleryVideo); })); }, + _renderYoutubeVideo: function(galleryVideo) { + //check if video already exists + if (galleryVideo.tagName === 'IFRAME') { + return; + } + //needed so the carousel gets resized and is visible + if (this.onlyYoutubeVideos) { + this.resizeCarousel(); + } + + var player; + var videoId = galleryVideo.id; + player = new YT.Player(videoId, { + height: this.itemHeight.toString(), + width: this.itemHeight * this._youtubeIframeRatio + 'px', + videoId: videoId, + events: { + 'onReady': onPlayerReady, + 'onError': onPlayerError + } + }); + this.own(player); + }, + _srcIsYoutubeVideo: function(src) { //taken from http://stackoverflow.com/questions/28735459/how-to-validate-youtube-url-in-client-side-in-text-box var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/; @@ -203,70 +286,43 @@ _setDefaultThumbsHeight: function() { if (!styles.getStyleSheet('defaultItemHeightImage')) { - styles.insertCssRule('.contentSlider .carouselScreenshot', lang.replace('max-height: {0}px', [this.itemHeight]), 'defaultItemHeightImage'); + styles.insertCssRule('.contentSlider .galleryImg', lang.replace('max-height: {0}px', [this.itemHeight]), 'defaultItemHeightImage'); } if (!styles.getStyleSheet('defaultItemHeightWrapper')) { - styles.insertCssRule('.contentSlider div', lang.replace('height: {0}px', [this.itemHeight]), 'defaultItemHeightWrapper'); + styles.insertCssRule('.contentSlider .galleryThumbWrapper', lang.replace('height: {0}px', [this.itemHeight]), 'defaultItemHeightWrapper'); } }, - renderNavButtons: function() { - this.leftButton = domConstruct.create('div', { - 'class': 'carouselButton leftCarouselButton', - onclick: lang.hitch(this, function() { - this.showItem(this.shownItemIndex - 1); - }) - }, this.contentSliderWrapper.domNode, 'before'); - domConstruct.create('div', { - 'class': 'carouselButtonImage' - }, this.leftButton); - - this.rightButton = domConstruct.create('div', { - 'class': 'carouselButton rightCarouselButton', - onclick: lang.hitch(this, function() { - this.showItem(this.shownItemIndex + 1); - }) - }, this.contentSliderWrapper.domNode, 'after'); - domConstruct.create('div', { - 'class': 'carouselButtonImage' - }, this.rightButton); - }, - - renderScaleButton: function() { - this.scaleButton = domConstruct.create('div', { - 'class': 'scaleButton dijitHidden', - onclick: lang.hitch(this, function() { - this.togglePreviewSize(this.shownItemIndex); - }) - }, this.domNode); - }, - - imagesLoaded: function() { - this.loadedImagesCount++; - if (this.loadedImagesCount === this.itemNodes.length) { + //checks if all divs in the contentSlider are ready + thumbLoaded: function() { + this.loadedThumbsCount++; + if (this.loadedThumbsCount === this.itemNodes.length) { this.allItemsLoaded = true; - this.heighestImg = this.heighestImg.cloneNode(); - domConstruct.place(this.heighestImg, this.domNode); - domClass.add(this.heighestImg, 'dijitHidden'); domClass.remove(this.scaleButton, 'dijitHidden'); - this._setDefaultThumbsHeight(); this.resizeCarousel(); - this.calcDefaultSliderWidth(); - this.calcOffsets(); + this._calcDefaultValues(); } }, _updateHeighestImage: function(img) { - if (!this.heighestImg) { - this.heighestImg = img; + if (img.naturalHeight > this.heighestImg.h) { + this.heighestImg.w = img.naturalWidth; + this.heighestImg.h = img.naturalHeight; + this.heighestImgRatio = img.naturalWidth / img.naturalHeight; } - if ((img.height > img.width) && (img.height > this.heighestImg.height)) { - this.heighestImg = img; + }, + + _calcDefaultValues: function() { + //check if carouselWidget is displayed + if (domGeometry.getMarginBox(this.domNode).w === 0) { + return; } + this._calcDefaultContentSliderWidth(); + this._calcDefaultContentSliderOffsets(); }, - calcDefaultSliderWidth: function() { + _calcDefaultContentSliderWidth: function() { this.defaultSliderWidth = domGeometry.getMarginBox(this.contentSlider.domNode).w; this.defaultItemWidths = []; array.forEach(this.itemNodes, lang.hitch(this, function(itemNode) { @@ -274,9 +330,8 @@ })); }, - calcOffsets: function() { - this.offsets = [0]; - var maxOffset = Math.max(0, this.defaultSliderWidth - domGeometry.getMarginBox(this.contentSliderWrapper.domNode).w); + _calcDefaultContentSliderOffsets: function() { + this.defaultContentSliderOffsets = [0]; for (var i = 1; i < this.itemNodes.length; i++) { var offset = 0; @@ -283,18 +338,17 @@ for (var c = 0; c < i; c++) { offset += this.defaultItemWidths[c]; } - if (offset >= maxOffset) { - this.offsets.push(maxOffset); - } else { - this.offsets.push(offset); - } + this.defaultContentSliderOffsets.push(offset); } }, resizeCarousel: function() { - if (this.bigThumbnails) { + if (this.isBigThumbnails) { this._resizeBigThumbnails(); + this._toggleNavButtonsVisibility(); + return; } + var totalItemsWidth = 0; array.forEach(this.itemNodes, function(imgWrapper) { var imgWrapperWidth = domGeometry.getMarginBox(imgWrapper).w; @@ -320,7 +374,9 @@ domStyle.set(this.outerContainer.domNode, 'width', availableWidth + 'px'); domStyle.set(this.contentSliderWrapper.domNode, 'width', widthForThumbs + 'px'); } - this._toggleNavButtonsVisibility(); + setTimeout(lang.hitch(this, function() { + this._toggleNavButtonsVisibility(); + }), 0); }, _resizeBigThumbnails: function(newIndex) { @@ -332,20 +388,10 @@ domClass.remove(this.rightButton, 'dijitHidden'); var maxWidth = domGeometry.getMarginBox(this.domNode).w - (domGeometry.getMarginBox(this.leftButton).w * 2) - marginOfThumbs; domStyle.set(this.outerContainer.domNode, 'width', ''); - domStyle.set(this.contentSliderWrapper.domNode, 'width', maxWidth + 'px'); + domStyle.set(this.contentSliderWrapper.domNode, 'width', maxWidth + marginOfThumbs + 'px'); - styles.disableStyleSheet('defaultItemHeightWrapper'); - - domStyle.set(this.heighestImg, 'position', 'absolute'); - domStyle.set(this.heighestImg, 'right', '1000000px'); - domClass.toggle(this.heighestImg, 'dijitHidden'); + var heighestImgHeight = Math.min(maxWidth / this.heighestImgRatio, maxHeight, this.heighestImg.h); - - domStyle.set(this.heighestImg, 'max-height', maxHeight + 'px'); - domStyle.set(this.heighestImg, 'max-width', maxWidth + 'px'); - var heighestImgHeight = domGeometry.getMarginBox(this.heighestImg).h; - domClass.toggle(this.heighestImg, 'dijitHidden'); - array.forEach(this.itemNodes, lang.hitch(this, function(imgWrapper) { domStyle.set(imgWrapper.firstChild, 'max-width', maxWidth + 'px'); domStyle.set(imgWrapper.firstChild, 'max-height', maxHeight + 'px'); @@ -352,14 +398,23 @@ domStyle.set(imgWrapper, 'height', heighestImgHeight + 'px'); domStyle.set(imgWrapper, 'width', maxWidth + 'px'); })); - query('.galleryVideo', this.contentSlider.domNode).forEach(lang.hitch(this, function(videoWrapper) { - domStyle.set(videoWrapper.firstChild, 'height', '100%'); + query('.galleryVideoWrapper', this.contentSlider.domNode).forEach(lang.hitch(this, function(videoWrapper) { + var height = maxWidth / this._youtubeIframeRatio; + domStyle.set(videoWrapper.firstChild, 'height', height + 'px'); domStyle.set(videoWrapper.firstChild, 'width', '100%'); })); domStyle.set(this.outerContainer.domNode, 'height', heighestImgHeight + 'px'); + newIndex = (newIndex === undefined) ? this.shownItemIndex : newIndex; var newOffset = newIndex * (maxWidth + marginOfThumbs); domStyle.set(this.contentSlider.domNode, 'left', (newOffset * (-1)) + 'px'); + this.contentSliderOffset = newOffset; + + var availableWidth = domGeometry.getMarginBox(this.domNode).w; + var widthForThumbs = availableWidth - + (domGeometry.getMarginBox(this.leftButton).w + domGeometry.getMarginBox(this.rightButton).w); + domStyle.set(this.outerContainer.domNode, 'width', availableWidth + 'px'); + domStyle.set(this.contentSliderWrapper.domNode, 'width', widthForThumbs + 'px'); }, _toggleNavButtonsVisibility: function(newOffset) { @@ -377,27 +432,23 @@ }, togglePreviewSize: function(newIndex) { - if (this.bigThumbnails) { - styles.enableStyleSheet('defaultItemHeightWrapper'); + if (this.isBigThumbnails) { var availableWidth = domGeometry.getMarginBox(this.domNode).w; if (availableWidth >= this.defaultSliderWidth) { domClass.add(this.leftButton, 'dijitHidden'); domClass.add(this.rightButton, 'dijitHidden'); - domStyle.set(this.outerContainer.domNode, 'transition', 'height 0.5s, width 0.5s'); - domStyle.set(this.contentSliderWrapper.domNode, 'transition', 'height 0.5s, width 0.5s'); domStyle.set(this.outerContainer.domNode, 'width', this.defaultSliderWidth + 'px'); domStyle.set(this.contentSliderWrapper.domNode, 'width', this.defaultSliderWidth + 'px'); } - - query('.carouselScreenshot', this.contentSlider.domNode).forEach(lang.hitch(this, function(imgNode) { + query('.galleryImg', this.contentSlider.domNode).forEach(lang.hitch(this, function(imgNode) { domStyle.set(imgNode, 'max-height', ''); domStyle.set(imgNode, 'max-width', ''); domStyle.set(imgNode.parentNode, 'width', ''); domStyle.set(imgNode.parentNode, 'height', ''); })); - query('.galleryVideo', this.contentSlider.domNode).forEach(lang.hitch(this, function(videoWrapper) { + query('.galleryVideoWrapper', this.contentSlider.domNode).forEach(lang.hitch(this, function(videoWrapper) { domStyle.set(videoWrapper, 'height', ''); domStyle.set(videoWrapper, 'width', ''); domStyle.set(videoWrapper.firstChild, 'height', ''); @@ -404,24 +455,32 @@ domStyle.set(videoWrapper.firstChild, 'width', ''); })); domStyle.set(this.outerContainer.domNode, 'height', this.itemHeight + 'px'); - domStyle.set(this.contentSlider.domNode, 'left', Math.abs(this.offsets[newIndex]) * (-1) + 'px'); + + //set offset for small thumbs + var maxOffset = Math.max(0, this.defaultSliderWidth - domGeometry.getMarginBox(this.contentSliderWrapper.domNode).w); + var newOffset = Math.min(this.defaultContentSliderOffsets[newIndex], maxOffset); + domStyle.set(this.contentSlider.domNode, 'left', Math.abs(newOffset) * (-1) + 'px'); + this.contentSliderOffset = newOffset; } else { - domStyle.set(this.outerContainer.domNode, 'transition', ''); - domStyle.set(this.contentSliderWrapper.domNode, 'transition', ''); + //scroll to the top of the carouselWidget + var scrollTarget = domGeometry.position(this.domNode, true).y - 50; + var scrollInterval = setInterval(lang.hitch(this, function() { + window.scrollTo(0, scrollTarget); + }), 5); + //wait for the transition to finish + setTimeout(function() { + clearInterval(scrollInterval); + }, 600); this._resizeBigThumbnails(newIndex); } - this.bigThumbnails = !this.bigThumbnails; + this.isBigThumbnails = !this.isBigThumbnails; domClass.toggle(this.scaleButton, 'minimize'); this.shownItemIndex = newIndex; setTimeout(lang.hitch(this, function() { - this.resizeCarousel(); - }), 600); - - //scroll to the top of the image - //var scrollTarget = domGeometry.position(this.domNode, true).y - 50; - //window.scrollTo(0, scrollTarget); + this._toggleNavButtonsVisibility(); + }), 550); }, showItem: function(newIndex) { @@ -452,21 +511,38 @@ this.showItem(newIndex -1); return; } + //take a higher or lower index if the offset would only change + //by a few pixels + if (newOffset < oldOffset && (oldOffset - newOffset) <= 70) { + this.showItem(newIndex -1); + return; + } else if (maxOffset > newOffset && (maxOffset - newOffset) <= 70) { + this.showItem(newIndex +1); + return; + } this.shownItemIndex = newIndex; domStyle.set(this.contentSlider.domNode, 'left', (newOffset * (-1)) + 'px'); + this.contentSliderOffset = newOffset; this._toggleNavButtonsVisibility(newOffset); }, _handleResize: function() { + if (domGeometry.getMarginBox(this.domNode).w === 0) { + return; + } if (this._resizeDeferred && !this._resizeDeferred.isFulfilled()) { this._resizeDeferred.cancel(); } this._resizeDeferred = tools.defer(lang.hitch(this, function() { this.resizeCarousel(); - this.calcOffsets(); - this.showItem(this.shownItemIndex); + if (!this.isBigThumbnails) { + setTimeout(lang.hitch(this, function() { + this.showItem(this.shownItemIndex); + }), 0); + } + this._toggleNavButtonsVisibility(); }), 200); this._resizeDeferred.otherwise(function() { /* prevent logging of exception */ }); }, @@ -474,17 +550,21 @@ startup: function() { this.inherited(arguments); this._registerAtParentOnShowEvents(lang.hitch(this, function() { - if (this.defaultSliderWidth === 0 && !this.bigThumbnails) { - this.calcDefaultSliderWidth(); + if (this.defaultSliderWidth === 0 && !this.isBigThumbnails) { + this._calcDefaultValues(); } if (this.allItemsLoaded) { this.resizeCarousel(); - this.showItem(this.shownItemIndex); + + if (!this.isBigThumbnails) { + setTimeout(lang.hitch(this, function() { + this.showItem(this.shownItemIndex); + }), 0); + } } })); this.own(on(baseWin.doc, 'resize', lang.hitch(this, '_handleResize'))); this.own(on(kernel.global, 'resize', lang.hitch(this, '_handleResize'))); - styles.enableStyleSheet('defaultItemHeightWrapper'); } }); }); Index: umc/js/appcenter.styl =================================================================== --- umc/js/appcenter.styl (Revision 67058) +++ umc/js/appcenter.styl (Arbeitskopie) @@ -465,29 +465,49 @@ left: 0 transition: left 0.5s - div + .galleryThumbWrapper margin: 0 10px display: inline-block - /*border: 2px solid darkgrey;*/ - /*box-sizing: content-box;*/ + vertical-align: middle + text-align: center + transition: height 0.5s, width 0.5s + &:after + content: '' + height: 100% + display: inline-block + vertical-align: middle - &.noTransition - transition: none !important + .galleryImgWrapper + &.brokenImg + width: 150px + box-shadow: inset 0px 0px 6px #5a5a5a + background: url("appcenter/iconmonstr-error-2.svg") no-repeat, #e6e6e6 + background-position: center center + background-size: 30% 30% - .carouselScreenshot - cursor: pointer - display: block - margin: auto - position: relative - top: 50% - transform: translateY(-50%) - -ms-transform: translateY(-50%) - -webkit-transform: translateY(-50%) - transition: max-height 0.5s, max-width 0.5s + .galleryImg + opacity: 0 + height: 100% + width: 100% + .galleryImg + cursor: pointer + transition: max-height 0.5s, max-width 0.5s + vertical-align: middle + + .galleryVideoWrapper + .galleryVideo + vertical-align: middle + + &.notLoadedBackground + box-shadow: inset 0px 0px 6px #5a5a5a + background: url("appcenter/iconmonstr-video-15.svg") no-repeat, #e6e6e6 + background-position: center center + background-size: 30% 30% + .carouselButton - float: left + //float: left cursor: pointer width: 40px @@ -513,9 +533,11 @@ &.rightCarouselButton margin-left: 5px + float: right &.leftCarouselButton margin-right: 5px + float: left .carouselButtonImage transform: rotateY(180deg)