Univention Bugzilla – Attachment 7523 Details for
Bug 39794
App Center - screenshot gallery
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
patch
thumbnail_gallery.patch (text/plain), 66.32 KB, created by
Johannes Keiser
on 2016-03-08 17:23 CET
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Johannes Keiser
Created:
2016-03-08 17:23 CET
Size:
66.32 KB
patch
obsolete
>Index: debian/univention-management-console-module-appcenter.install >=================================================================== >--- debian/univention-management-console-module-appcenter.install (Revision 67996) >+++ debian/univention-management-console-module-appcenter.install (Arbeitskopie) >@@ -12,3 +12,5 @@ > umc/js/appcenter/star.svg usr/share/univention-management-console-frontend/js/umc/modules/appcenter > umc/js/appcenter/carouselArrowRight.svg usr/share/univention-management-console-frontend/js/umc/modules/appcenter > umc/js/appcenter/statusIcons.svg usr/share/univention-management-console-frontend/js/umc/modules/appcenter >+umc/js/appcenter/thumbnailError.svg usr/share/univention-management-console-frontend/js/umc/modules/appcenter >+umc/js/appcenter/videoPlayButton.svg usr/share/univention-management-console-frontend/js/umc/modules/appcenter >Index: umc/js/appcenter/AppDetailsPage.js >=================================================================== >--- umc/js/appcenter/AppDetailsPage.js (Revision 67996) >+++ umc/js/appcenter/AppDetailsPage.js (Arbeitskopie) >@@ -63,9 +63,9 @@ > "umc/widgets/Grid", > "umc/modules/appcenter/AppCenterGallery", > "umc/modules/appcenter/App", >- "umc/modules/appcenter/Carousel", >+ "umc/modules/appcenter/ThumbnailGallery", > "umc/i18n!umc/modules/appcenter" >-], function(declare, lang, kernel, array, dojoEvent, all, json, when, query, ioQuery, topic, Deferred, domConstruct, domClass, on, domStyle, Memory, Observable, Tooltip, Lightbox, entities, UMCApplication, tools, dialog, TitlePane, ContainerWidget, ProgressBar, Page, Text, Button, CheckBox, Grid, AppCenterGallery, App, Carousel, _) { >+], function(declare, lang, kernel, array, dojoEvent, all, json, when, query, ioQuery, topic, Deferred, domConstruct, domClass, on, domStyle, Memory, Observable, Tooltip, Lightbox, entities, UMCApplication, tools, dialog, TitlePane, ContainerWidget, ProgressBar, Page, Text, Button, CheckBox, Grid, AppCenterGallery, App, ThumbnailGallery, _) { > > var adaptedGrid = declare([Grid], { > _updateContextActions: function() { >@@ -554,10 +554,10 @@ > src: ithumb > }; > }); >- this.carousel = new Carousel({ >+ this.thumbnailGallery = new ThumbnailGallery({ > items: urls > }); >- styleContainer.addChild(this.carousel); >+ styleContainer.addChild(this.thumbnailGallery); > this._detailsContainer.addChild(styleContainer); > } > >@@ -568,6 +568,22 @@ > content: this._detailsContainer, > 'class': 'appDetailsPane' > }); >+ >+ //handle behaviour of the thumbnailGallery based on wether >+ //the titlepane is closed or not >+ if (!detailsPane.open) { >+ this.thumbnailGallery._stopFirstResize = true; >+ } >+ detailsPane.watch('open', lang.hitch(this, function(variable, oldVal, titlePaneIsOpen) { >+ if (titlePaneIsOpen) { >+ this.thumbnailGallery._handleResize(); >+ } else { >+ if (this.thumbnailGallery.isBigThumbnails) { >+ this.thumbnailGallery.toggleThumbSize(); >+ } >+ this.thumbnailGallery.pauseAllVideos(); >+ } >+ })); > this._mainRegionContainer.addChild(detailsPane, isAppInstalled ? null : 0); > }, > >Index: umc/js/appcenter/Carousel.js >=================================================================== >--- umc/js/appcenter/Carousel.js (Revision 67996) >+++ umc/js/appcenter/Carousel.js (Arbeitskopie) >@@ -1,490 +0,0 @@ >-/* >- * Copyright 2011-2016 Univention GmbH >- * >- * http://www.univention.de/ >- * >- * All rights reserved. >- * >- * The source code of this program is made available >- * under the terms of the GNU Affero General Public License version 3 >- * (GNU AGPL V3) as published by the Free Software Foundation. >- * >- * Binary versions of this program provided by Univention to you as >- * well as other copyrighted, protected or trademarked materials like >- * Logos, graphics, fonts, specific documentations and configurations, >- * cryptographic keys etc. are subject to a license agreement between >- * you and Univention and not subject to the GNU AGPL V3. >- * >- * In the case you use this program under the terms of the GNU AGPL V3, >- * the program is provided in the hope that it will be useful, >- * but WITHOUT ANY WARRANTY; without even the implied warranty of >- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >- * GNU Affero General Public License for more details. >- * >- * You should have received a copy of the GNU Affero General Public >- * License with the Debian GNU/Linux or Univention distribution in file >- * /usr/share/common-licenses/AGPL-3; if not, see >- * <http://www.gnu.org/licenses/>. >- */ >-/*global define,console,require*/ >- >-define([ >- "dojo/_base/declare", >- "dojo/_base/array", >- "dojo/_base/lang", >- "dojo/_base/kernel", >- "dojo/_base/window", >- "dojo/on", >- "dojo/query", >- "dojo/dom-construct", >- "dojo/dom-style", >- "dojo/dom-geometry", >- "dojo/dom-class", >- "dojox/html/styles", >- "umc/tools", >- "umc/widgets/ContainerWidget", >- "umc/widgets/_RegisterOnShowMixin", >- "dojo/domReady!" >-], function(declare, array, lang, kernel, baseWin, on, query, domConstruct, domStyle, domGeometry, domClass, styles, tools, ContainerWidget, _RegisterOnShowMixin) { >- return declare("umc.modules.appcenter.Carousel_new", [ContainerWidget, _RegisterOnShowMixin], { >- baseClass: 'umcCarouselWidget', >- >- outerContainer: null, >- contentSlider: null, >- contentSliderOffset: null, >- >- shownItemIndex: null, >- >- itemHeight: null, >- heighestImg: null, >- >- // items: Array >- // array of objects({src: <src-string>}) >- // where <src-string> is either an image or a youtube video url >- items: null, >- itemNodes: null, >- >- allItemsLoaded: null, >- >- bigThumbnails: null, >- >- _resizeDeferred: null, >- >- postMixInProperties: function() { >- this.itemHeight = this.itemHeight || 200; >- this.itemNodes = []; >- this.contentSliderOffset = 0; >- this.shownItemIndex = 0; >- this.allItemsLoaded = false; >- this.bigThumbnails = false; >- }, >- >- buildRendering: function() { >- this.inherited(arguments); >- >- 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); >- } else { >- //load youtube api >- var tag = document.createElement('script'); >- tag = domConstruct.create('script', { >- id: "youtubeAPI", >- src: "https://www.youtube.com/iframe_api" >- }); >- var firstScriptTag = document.getElementsByTagName('script')[0]; >- firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); >- >- window.onYouTubeIframeAPIReady = lang.hitch(this, function() { >- this._renderYoutubeVideos(); >- }); >- } >- onPlayerReady = lang.hitch(this, function() { >- this.imagesLoaded(); >- }); >- }, >- >- renderContentSlider: function() { >- this.contentSliderWrapper = new ContainerWidget({ >- 'class': 'contentSliderWrapper' >- }); >- this.contentSlider = new ContainerWidget({ >- 'class': 'contentSlider' >- }); >- this.contentSliderWrapper.addChild(this.contentSlider); >- this.outerContainer.addChild(this.contentSliderWrapper); >- >- this._renderThumbs(); >- }, >- >- _renderThumbs: function() { >- this.loadedImagesCount = 0; >- var index = 0; >- var uniqueYTVideoIds = []; >- >- array.forEach(this.items, lang.hitch(this, function(item) { >- if (this._srcIsYoutubeVideo(item.src)) { >- var videoId = this._getYoutubeUrlVideoId(item.src); >- if (uniqueYTVideoIds.indexOf(videoId) !== -1) { >- return; >- } >- uniqueYTVideoIds.push(videoId); >- >- var videoWrapper = domConstruct.create('div', {'class': 'galleryVideo'}, this.contentSlider.domNode); >- var div = domConstruct.create('div', { >- id: videoId >- }, videoWrapper); >- >- this.itemNodes.push(videoWrapper); >- } else { >- var imgWrapper = domConstruct.create('div', {}, this.contentSlider.domNode); >- var img = domConstruct.create('img', { >- src: item.src, >- index: index, >- 'class': 'carouselScreenshot', >- onload: lang.hitch(this, function() { >- this._updateHeighestImage(img); >- this.imagesLoaded(); >- }), >- onclick: lang.hitch(this, function(evt) { >- this.togglePreviewSize(parseInt(evt.target.getAttribute('index'))); >- }) >- }, imgWrapper); >- this.itemNodes.push(imgWrapper); >- } >- index++; >- })); >- }, >- >- _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); >- })); >- }, >- >- _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+)?$/; >- if(src.match(p)){ >- return true; >- } >- return false; >- }, >- >- _getYoutubeUrlVideoId: function(src) { >- var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/; >- return src.match(p)[1]; >- }, >- >- _setDefaultThumbsHeight: function() { >- if (!styles.getStyleSheet('defaultItemHeightImage')) { >- styles.insertCssRule('.contentSlider .carouselScreenshot', 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'); >- } >- }, >- >- 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) { >- 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(); >- } >- }, >- >- _updateHeighestImage: function(img) { >- if (!this.heighestImg) { >- this.heighestImg = img; >- } >- if ((img.height > img.width) && (img.height > this.heighestImg.height)) { >- this.heighestImg = img; >- } >- }, >- >- calcDefaultSliderWidth: function() { >- this.defaultSliderWidth = domGeometry.getMarginBox(this.contentSlider.domNode).w; >- this.defaultItemWidths = []; >- array.forEach(this.itemNodes, lang.hitch(this, function(itemNode) { >- this.defaultItemWidths.push(domGeometry.getMarginBox(itemNode).w); >- })); >- }, >- >- calcOffsets: function() { >- this.offsets = [0]; >- var maxOffset = Math.max(0, this.defaultSliderWidth - domGeometry.getMarginBox(this.contentSliderWrapper.domNode).w); >- >- for (var i = 1; i < this.itemNodes.length; i++) { >- var offset = 0; >- for (var c = 0; c < i; c++) { >- offset += this.defaultItemWidths[c]; >- } >- if (offset >= maxOffset) { >- this.offsets.push(maxOffset); >- } else { >- this.offsets.push(offset); >- } >- } >- }, >- >- resizeCarousel: function() { >- if (this.bigThumbnails) { >- this._resizeBigThumbnails(); >- } >- var totalItemsWidth = 0; >- array.forEach(this.itemNodes, function(imgWrapper) { >- var imgWrapperWidth = domGeometry.getMarginBox(imgWrapper).w; >- totalItemsWidth += imgWrapperWidth; >- }); >- >- var contentSliderHeight = domGeometry.getMarginBox(this.contentSlider.domNode).h; >- domStyle.set(this.outerContainer.domNode, 'height', contentSliderHeight + 'px'); >- >- var availableWidth = domGeometry.getMarginBox(this.domNode).w; >- >- if (availableWidth >= totalItemsWidth) { >- domClass.add(this.leftButton, 'dijitHidden'); >- domClass.add(this.rightButton, 'dijitHidden'); >- domStyle.set(this.outerContainer.domNode, 'width', totalItemsWidth + 'px'); >- domStyle.set(this.contentSliderWrapper.domNode, 'width', totalItemsWidth + 'px'); >- } else { >- domClass.remove(this.leftButton, 'dijitHidden'); >- domClass.remove(this.rightButton, 'dijitHidden'); >- >- 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'); >- } >- this._toggleNavButtonsVisibility(); >- }, >- >- _resizeBigThumbnails: function(newIndex) { >- var maxHeight = dojo.window.getBox().h - 200; >- maxHeight = (maxHeight < this.itemHeight) ? this.itemHeight : maxHeight; >- >- var marginOfThumbs = domGeometry.getMarginExtents(this.itemNodes[0]).w; >- domClass.remove(this.leftButton, 'dijitHidden'); //make sure navButton is visible for sizing calculations >- 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'); >- >- styles.disableStyleSheet('defaultItemHeightWrapper'); >- >- domStyle.set(this.heighestImg, 'position', 'absolute'); >- domStyle.set(this.heighestImg, 'right', '1000000px'); >- domClass.toggle(this.heighestImg, 'dijitHidden'); >- >- >- 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'); >- 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%'); >- domStyle.set(videoWrapper.firstChild, 'width', '100%'); >- })); >- domStyle.set(this.outerContainer.domNode, 'height', heighestImgHeight + 'px'); >- >- var newOffset = newIndex * (maxWidth + marginOfThumbs); >- domStyle.set(this.contentSlider.domNode, 'left', (newOffset * (-1)) + 'px'); >- }, >- >- _toggleNavButtonsVisibility: function(newOffset) { >- var _contentSliderOffset; >- if (newOffset === undefined) { >- _contentSliderOffset = Math.abs(domStyle.get(this.contentSlider.domNode, 'left')); >- } else { >- _contentSliderOffset = newOffset; >- } >- >- var maxOffset = domGeometry.getMarginBox(this.contentSlider.domNode).w - domGeometry.getMarginBox(this.contentSliderWrapper.domNode).w; >- >- domClass.toggle(this.leftButton, 'disabled', (_contentSliderOffset === 0 || this.shownItemIndex === 0)); >- domClass.toggle(this.rightButton, 'disabled', (_contentSliderOffset === maxOffset || this.shownItemIndex === this.items.length-1)); >- }, >- >- togglePreviewSize: function(newIndex) { >- if (this.bigThumbnails) { >- styles.enableStyleSheet('defaultItemHeightWrapper'); >- 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) { >- 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) { >- domStyle.set(videoWrapper, 'height', ''); >- domStyle.set(videoWrapper, 'width', ''); >- domStyle.set(videoWrapper.firstChild, 'height', ''); >- 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'); >- >- } else { >- domStyle.set(this.outerContainer.domNode, 'transition', ''); >- domStyle.set(this.contentSliderWrapper.domNode, 'transition', ''); >- this._resizeBigThumbnails(newIndex); >- } >- this.bigThumbnails = !this.bigThumbnails; >- 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); >- }, >- >- showItem: function(newIndex) { >- if (newIndex < 0 || newIndex >= this.itemNodes.length) { >- return; >- } >- >- var newOffset = 0; >- >- var neededOffset = 0; >- for (var i = 0; i < newIndex; i++) { >- var itemWidth = domGeometry.getMarginBox(this.itemNodes[i]).w; >- neededOffset += itemWidth; >- } >- >- var maxOffset = domGeometry.getMarginBox(this.contentSlider.domNode).w - domGeometry.getMarginBox(this.contentSliderWrapper.domNode).w; >- if (neededOffset >= maxOffset) { >- newOffset = maxOffset; >- } else { >- newOffset = neededOffset; >- } >- >- var oldOffset = Math.abs(domStyle.get(this.contentSlider.domNode, 'left')); >- >- //if the new index would not change the offset >- //take the next lower index till a new offset is found >- if (oldOffset === newOffset && newIndex < this.shownItemIndex) { >- this.showItem(newIndex -1); >- return; >- } >- >- this.shownItemIndex = newIndex; >- domStyle.set(this.contentSlider.domNode, 'left', (newOffset * (-1)) + 'px'); >- >- this._toggleNavButtonsVisibility(newOffset); >- }, >- >- _handleResize: function() { >- 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); >- }), 200); >- this._resizeDeferred.otherwise(function() { /* prevent logging of exception */ }); >- }, >- >- startup: function() { >- this.inherited(arguments); >- this._registerAtParentOnShowEvents(lang.hitch(this, function() { >- if (this.defaultSliderWidth === 0 && !this.bigThumbnails) { >- this.calcDefaultSliderWidth(); >- } >- if (this.allItemsLoaded) { >- this.resizeCarousel(); >- this.showItem(this.shownItemIndex); >- } >- })); >- 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/ThumbnailGallery.js >=================================================================== >--- umc/js/appcenter/ThumbnailGallery.js (Revision 0) >+++ umc/js/appcenter/ThumbnailGallery.js (Arbeitskopie) >@@ -0,0 +1,1052 @@ >+/* >+ * Copyright 2011-2016 Univention GmbH >+ * >+ * http://www.univention.de/ >+ * >+ * All rights reserved. >+ * >+ * The source code of this program is made available >+ * under the terms of the GNU Affero General Public License version 3 >+ * (GNU AGPL V3) as published by the Free Software Foundation. >+ * >+ * Binary versions of this program provided by Univention to you as >+ * well as other copyrighted, protected or trademarked materials like >+ * Logos, graphics, fonts, specific documentations and configurations, >+ * cryptographic keys etc. are subject to a license agreement between >+ * you and Univention and not subject to the GNU AGPL V3. >+ * >+ * In the case you use this program under the terms of the GNU AGPL V3, >+ * the program is provided in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU Affero General Public License for more details. >+ * >+ * You should have received a copy of the GNU Affero General Public >+ * License with the Debian GNU/Linux or Univention distribution in file >+ * /usr/share/common-licenses/AGPL-3; if not, see >+ * <http://www.gnu.org/licenses/>. >+ */ >+/*global define,console,require*/ >+ >+define([ >+ "dojo/_base/declare", >+ "dojo/_base/array", >+ "dojo/_base/lang", >+ "dojo/_base/kernel", >+ "dojo/_base/window", >+ "dojo/on", >+ "dojo/query", >+ "dojo/dom-construct", >+ "dojo/dom-style", >+ "dojo/dom-geometry", >+ "dojo/dom-class", >+ "dojox/html/styles", >+ "umc/tools", >+ "umc/widgets/ContainerWidget" >+], function(declare, array, lang, kernel, baseWin, on, query, domConstruct, domStyle, domGeometry, domClass, styles, tools, ContainerWidget) { >+ return declare("umc.modules.appcenter.ThumbnailGallery", [ContainerWidget], { >+ baseClass: 'umcThumbnailGallery', >+ >+ outerContainer: null, >+ >+ //is the viewport for the contentSlider >+ contentSliderWrapper: null, >+ >+ //the contentSlider contains all thumbs >+ //the offset of the contentSlider gets changed to show different thumbs >+ contentSlider: null, >+ >+ //the current offset off the contentSlider as absolute value ignoring navButtons >+ //used for calculations >+ contentSliderOffset: null, >+ >+ //the currently displayed offset as absolute value >+ //the navButtons lay on top of the contentSlider but the calculations ignore that fact. so the width of one or >+ //both navButtons have to be accounted after the fact >+ _visibleOffset: null, >+ >+ //toggles thumb size >+ scaleButton: null, >+ >+ //all ThumbNodes that are in the contentSlider >+ itemNodes: null, >+ >+ //shownItemIndex: int >+ // The currently visible thumb (itemNodes[shownItemIndex]). >+ // In the small view the shownItemIndex is either the leftmost or rightmost thumb >+ // based on the last call of showPrevThumbs or showNextThumbs. >+ // In the big view it is the visible thumb. >+ shownItemIndex: null, >+ >+ //the default height for gallery thumbs in the small view >+ defaultThumbHeight: null, >+ >+ //heighestImg: {w: number, h: number} >+ // the natural width and height of the heighest img in the contentSlider >+ heighestImg: null, >+ >+ //heighestImgRatio = heighestImg.w / heighestImg.h >+ // If there are only videos in the contentSlider >+ // the heighestImgRatio defaults to the _youtubeIframeRatio >+ // to determine the height for big Thumbnails >+ heighestImgRatio: null, >+ >+ //used to check if the contentSliderWrapper is to small for showNextThumbs and showPrevThumbs to work correctly >+ //and change behaviour accordingly >+ widestDefaultThumbWidth: null, >+ >+ //_youtubeIframeRatio: defaults to 16/9 >+ _youtubeIframeRatio: null, >+ >+ // items: Array >+ // array of received objects({src: <src-string>}) >+ // where <src-string> is either an image or a youtube video url >+ items: null, >+ >+ //preparedItems: Array >+ // array of objects derived from items. >+ // Duplicate youtube videos are removed and >+ // objects are marked as either 'img' or 'video' >+ preparedItems: null, >+ >+ //allItemsLoaded: bool >+ allItemsLoaded: null, >+ >+ _loadedThumbsCount: null, >+ >+ //isBigThumbnails: bool >+ isBigThumbnails: null, >+ >+ //the margin each thumb has on either side >+ _galleryThumbLeftRightMargin: null, >+ //the whole left and right margin for thumbs >+ _galleryThumbMarginExtents: null, >+ >+ //naturalThumbDimensions: object{<thumbIndex>: {w: <width>, h: <height>}} >+ // stores the unscaled width and height of the images. >+ // defaults to w: 1600, h: 900 for videos >+ naturalThumbDimensions: null, >+ >+ //defaultThumbWidths: object{<thumbIndex>: <width + this._galleryThumbMarginExtents>} >+ // The default width for all thumbs in the small view including this._galleryThumbMarginExtents >+ defaultThumbWidths: null, >+ >+ //defaultThumbOffsets: array >+ // contains the offset for every thumb so it is the leftmost first visible thumb >+ defaultThumbOffsets: null, >+ >+ //ytPlayers: Array >+ // array of youtube Player objects for every video in the Gallery >+ // ( https://developers.google.com/youtube/iframe_api_reference?hl=de#Loading_a_Video_Player ) >+ // used to pause videos if they are no longer visible >+ ytPlayers: null, >+ >+ //thumbIndexToVideoId: object >+ // maps the id of the videoThumb to its youtube video_id >+ thumbIndexToVideoId: null, >+ videoIdToThumbIndex: null, >+ >+ playingVideos: null, >+ >+ //_insertedCssRules: Array >+ // contains array with objects with the selector and declaration inserted via styles.insertCssRule. >+ // {selector: <selector>, declaration: <declaration>} >+ _insertedCssRules: null, >+ >+ _resizeDeferred: null, >+ >+ _firstResizeInterval: null, >+ >+ _stopFirstResize: null, >+ >+ //_baseTransitionDuration: int in ms >+ _baseTransitionDuration: null, >+ >+ postMixInProperties: function() { >+ this.preparedItems = []; >+ this.defaultThumbHeight = this.defaultThumbHeight || 200; >+ this.itemNodes = []; >+ this.contentSliderOffset = 0; >+ this._visibleOffset = 0; >+ this.shownItemIndex = 0; >+ this.allItemsLoaded = false; >+ this.isBigThumbnails = false; >+ this._youtubeIframeRatio = 16 / 9; >+ //if there are only youtube videos in the contentslider >+ //the height for big thumbnails is determined by the _youtubeIframeRatio >+ this.heighestImgRatio = this._youtubeIframeRatio; >+ this.heighestImg = {w: 0, h: 0}; >+ this.widestDefaultThumbWidth = 0; >+ this._galleryThumbLeftRightMargin = 10; >+ this._galleryThumbMarginExtents = 2 * this._galleryThumbLeftRightMargin; >+ this.naturalThumbDimensions = {}; >+ this.defaultThumbWidths = {}; >+ this.ytPlayers = {}; >+ this.thumbIndexToVideoId = {}; >+ this.videoIdToThumbIndex = {}; >+ this.playingVideos = {}; >+ this._insertedCssRules = []; >+ this._totalWidthOfSmallThumbs = 0; >+ this._bigThumbDimensions = {}; >+ this._smallMaxOffset = 0; >+ this._widthForThumbs = 0; >+ this.loaded = false; >+ this._smallViewHasNavButtons = false; >+ this._stopFirstResize = false; >+ this._baseTransitionDuration = 500; >+ }, >+ >+ postCreate: function() { >+ //check if youtube iframe api is already loaded >+ if (window.YT && window.YT.loaded) { >+ //stub >+ } else { >+ //load youtube iframe api >+ var tag = document.createElement('script'); >+ tag = domConstruct.create('script', { >+ id: "youtubeAPI", >+ src: "https://www.youtube.com/iframe_api" >+ }); >+ var firstScriptTag = document.getElementsByTagName('script')[0]; >+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); >+ } >+ }, >+ >+ buildRendering: function() { >+ this.inherited(arguments); >+ >+ this._insertGalleryVideoDefaultDimensions(); >+ this._insertGalleryThumbCssRules(); >+ this._insertTransitionDurations(); >+ >+ //style needed while thumbs are getting loaded >+ domStyle.set(this.domNode, 'height', this.defaultThumbHeight + 'px'); >+ domStyle.set(this.domNode, 'overflow', 'hidden'); >+ >+ this.galleryLoadingOverlay = domConstruct.create('div', { >+ 'class': 'galleryLoadingOverlay' >+ }, this.domNode); >+ >+ this.outerContainer = new ContainerWidget({ >+ 'class': 'galleryOuterContainer' >+ }); >+ 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() { >+ //construct left and right navButtons >+ this.leftButton = domConstruct.create('div', { >+ 'class': 'galleryNavButton leftGalleryNavButton disabled' >+ }, this.contentSliderWrapper.domNode, 'before'); >+ on(this.leftButton, 'click', lang.hitch(this, function() { >+ this.showPrevThumbs(); >+ })); >+ domConstruct.create('div', { >+ 'class': 'galleryNavButtonImage' >+ }, this.leftButton); >+ >+ this.rightButton = domConstruct.create('div', { >+ 'class': 'galleryNavButton rightGalleryNavButton disabled' >+ }, this.contentSliderWrapper.domNode, 'after'); >+ on(this.rightButton, 'click', lang.hitch(this, function() { >+ this.showNextThumbs(); >+ })); >+ domConstruct.create('div', { >+ 'class': 'galleryNavButtonImage' >+ }, this.rightButton); >+ >+ //insert Css Rule >+ var selector = lang.replace('#{0} .galleryNavButton', [this.id]); >+ var declaration = lang.replace('height: {0}px; transition-duration: {1}ms', [this.defaultThumbHeight, this._baseTransitionDuration]); >+ styles.insertCssRule(selector, declaration); >+ this._insertedCssRules.push({selector: selector, declaration: declaration}); >+ }, >+ >+ renderScaleButton: function() { >+ this.scaleButton = domConstruct.create('div', { >+ 'class': 'scaleButton dijitHidden', >+ onclick: lang.hitch(this, function() { >+ this.toggleThumbSize(this.shownItemIndex); >+ }) >+ }, this.domNode); >+ }, >+ >+ renderContentSlider: function() { >+ this.contentSlider = new ContainerWidget({ >+ 'class': 'contentSlider' >+ }); >+ >+ this.galleryThumbVerticalAlignHelper = domConstruct.create('div', { >+ 'class': 'galleryThumb verticalAlignHelper' >+ }, this.contentSlider.domNode); >+ >+ this.contentSliderWrapper.addChild(this.contentSlider); >+ >+ this._renderThumbs(); >+ }, >+ >+ _renderThumbs: function() { >+ this._prepareItems(); >+ this._loadedThumbsCount = 0; >+ >+ array.forEach(this.preparedItems, lang.hitch(this, function(item, index) { >+ if (item.type === 'video') { >+ this._createVideoThumb(item, index); >+ } else { >+ this._createImgThumb(item, index); >+ } >+ })); >+ }, >+ >+ _prepareItems: function() { >+ var uniqueYTVideoIds = []; >+ >+ array.forEach(this.items, lang.hitch(this, function(item, index) { >+ if (this._srcIsYoutubeVideo(item.src)) { >+ var videoId = this._getYoutubeUrlVideoId(item.src); >+ if (uniqueYTVideoIds.indexOf(videoId) !== -1) { >+ return; >+ } >+ uniqueYTVideoIds.push(videoId); >+ this.preparedItems.push({type: 'video', videoId: videoId}); >+ } else { >+ this.preparedItems.push({type: 'img', src: item.src}); >+ } >+ })); >+ }, >+ >+ _createVideoThumb: function(item, index) { >+ var videoId = item.videoId; >+ >+ //get the thumbnail for the youtube video via the unique id >+ var ytVideoThumbnailURL = lang.replace('https://img.youtube.com/vi/{0}/hqdefault.jpg', [videoId]); >+ >+ var galleryVideoWrapper = domConstruct.create('div', { >+ id: 'galleryThumb_' + index, >+ 'class': 'galleryThumb galleryVideoThumb galleryVideoWrapper' >+ }, this.contentSlider.domNode); >+ >+ //show the thumbnail of the video with a playbutton >+ var thumbNailWrapper = domConstruct.create('div', { >+ 'class': 'galleryVideoThumbnailWrapper' >+ }, galleryVideoWrapper); >+ >+ var thumbNail = domConstruct.create('div', { >+ 'class': 'galleryVideoThumbnail' >+ }, thumbNailWrapper); >+ var playButtonImg = domConstruct.create('div', { >+ 'class': 'galleryVideoPlayButtonIcon' >+ }, thumbNailWrapper); >+ >+ //this div gets replaced by the youtube iframe >+ var galleryVideo = domConstruct.create('div', { >+ 'class': 'galleryVideo dijitHidden', >+ id: videoId >+ }, galleryVideoWrapper); >+ >+ //set the thumbnail of the ytVideo as Background >+ var selector = lang.replace('#{0} #galleryThumb_{1} .galleryVideoThumbnail', [this.id, index]); >+ var declaration = lang.replace('background-image: url({0})', [ytVideoThumbnailURL]); >+ styles.insertCssRule(selector, declaration); >+ this._insertedCssRules.push({selector: selector, declaration: declaration}); >+ >+ //load youtube video >+ on(galleryVideoWrapper, 'click', lang.hitch(this, function() { >+ this.shownItemIndex = index; >+ if (window.YT && window.YT.loaded) { >+ this.showThumb(this.shownItemIndex); >+ domClass.add(galleryVideoWrapper, 'loaded'); >+ domClass.remove(galleryVideo, 'dijitHidden'); >+ domClass.add(playButtonImg, 'dijitHidden'); >+ domClass.add(thumbNailWrapper, 'dijitHidden'); >+ setTimeout(lang.hitch(this, function() { >+ this._renderYoutubeVideo(galleryVideo, index); >+ }), 0); >+ } >+ })); >+ >+ this.naturalThumbDimensions[index] = {w: 1600, h: 900}; >+ var w = Math.round(this.defaultThumbHeight * this._youtubeIframeRatio); >+ var h = this.defaultThumbHeight; >+ this.defaultThumbWidths[index] = w + this._galleryThumbMarginExtents; >+ this._updateWidestThumb(w); >+ >+ this.itemNodes.push(galleryVideoWrapper); >+ item.domNode = galleryVideoWrapper; >+ this.thumbLoaded(); >+ }, >+ >+ _createImgThumb: function(item, index) { >+ var imgUrl = item.src; >+ var galleryImgThumb = domConstruct.create('div', { >+ 'class': 'galleryThumb galleryImgThumb', >+ id: 'galleryThumb_' + index >+ }, this.contentSlider.domNode); >+ >+ var img = domConstruct.create('img', { >+ src: imgUrl, >+ onload: lang.hitch(this, function() { >+ this._updateHeighestImage(img); >+ this.naturalThumbDimensions[index] = {w: img.naturalWidth, h: img.naturalHeight}; >+ >+ //calc the width and height for the thumb in the small view >+ var w = Math.round(this.defaultThumbHeight * (img.naturalWidth / img.naturalHeight)); >+ var h = this.defaultThumbHeight; >+ this.defaultThumbWidths[index] = w + this._galleryThumbMarginExtents; >+ this._updateWidestThumb(w); >+ >+ //insert img as background >+ var selector = lang.replace('#{0} #{1}', [this.id, galleryImgThumb.id]); >+ var declaration = lang.replace('width: {0}px; height: {1}px; background-image: url({2})', [w, h, img.src]); >+ styles.insertCssRule(selector, declaration); >+ this._insertedCssRules.push({selector: selector, declaration: declaration}); >+ >+ this.thumbLoaded(); >+ }), >+ onerror: lang.hitch(this, function() { >+ //calc the width and height for the thumb in the small view >+ var w = Math.round(this.defaultThumbHeight * (3/4)); >+ var h = this.defaultThumbHeight; >+ this.naturalThumbDimensions[index] = {w: w, h: h}; >+ this.defaultThumbWidths[index] = w + this._galleryThumbMarginExtents; >+ this._updateWidestThumb(w); >+ >+ //insert img as background >+ var selector = lang.replace('#{0} #{1}', [this.id, galleryImgThumb.id]); >+ var declaration = lang.replace('width: {0}px; height: {1}px;', [w, h]); >+ styles.insertCssRule(selector, declaration); >+ this._insertedCssRules.push({selector: selector, declaration: declaration}); >+ domClass.add(galleryImgThumb, 'brokenImg'); >+ >+ this.thumbLoaded(); >+ }) >+ }); >+ >+ on(galleryImgThumb, 'click', lang.hitch(this, function() { >+ this.toggleThumbSize(index); >+ })); >+ this.itemNodes.push(galleryImgThumb); >+ item.domNode = galleryImgThumb; >+ }, >+ >+ _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+)?$/; >+ if(src.match(p)){ >+ return true; >+ } >+ return false; >+ }, >+ >+ _getYoutubeUrlVideoId: function(src) { >+ var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/; >+ return src.match(p)[1]; >+ }, >+ >+ _insertGalleryVideoDefaultDimensions: function() { >+ //calc default width and height >+ var width = Math.round(this.defaultThumbHeight * this._youtubeIframeRatio); >+ var height = this.defaultThumbHeight; >+ >+ //insert Css Rule >+ var selector = lang.replace('#{0}.{1} .contentSlider .galleryVideoWrapper', [this.id, this.baseClass]); >+ var declaration = lang.replace('width: {0}px; height: {1}px', [width, height]); >+ styles.insertCssRule(selector, declaration); >+ this._insertedCssRules.push({selector: selector, declaration: declaration}); >+ }, >+ >+ _insertGalleryThumbCssRules: function() { >+ var selector = lang.replace('#{0} .contentSlider .galleryThumb', [this.id]); >+ var declaration = lang.replace('margin: 0 {0}px; transition-duration: {1}ms', [this._galleryThumbLeftRightMargin, this._baseTransitionDuration]); >+ styles.insertCssRule(selector, declaration); >+ this._insertedCssRules.push({ selector: selector, declaration: declaration }); >+ }, >+ >+ _insertTransitionDurations: function() { >+ var selector; >+ var declaration; >+ //contentSlider >+ selector = lang.replace('#{0} .contentSlider', [this.id]); >+ declaration = lang.replace('transition-duration: {0}ms', [this._baseTransitionDuration]); >+ styles.insertCssRule(selector, declaration); >+ this._insertedCssRules.push({ selector: selector, declaration: declaration }); >+ }, >+ >+ _renderYoutubeVideo: function(galleryVideo, index) { >+ var player; >+ var videoId = galleryVideo.id; >+ //add the youtube video via the youtube iframe api >+ player = new YT.Player(videoId, { >+ videoId: videoId, >+ events: { >+ 'onReady': lang.hitch(this, this.onPlayerReady), >+ 'onStateChange': lang.hitch(this, this.onPlayerStateChange) >+ } >+ }); >+ this.own(player); >+ >+ //safe a reference to the video id accessible through the thumbIndex and vice versa >+ this.thumbIndexToVideoId[index] = videoId; >+ this.videoIdToThumbIndex[videoId] = index; >+ //safe the youtube player object >+ this.ytPlayers[videoId] = {playerIndex: index}; >+ }, >+ >+ onPlayerReady: function(evt) { >+ evt.target.playVideo(); >+ var videoId = evt.target.getVideoData().video_id; >+ this.ytPlayers[videoId].player = evt.target; >+ }, >+ >+ onPlayerStateChange: function(evt) { >+ var videoId; >+ if (evt.data && evt.data === YT.PlayerState.PLAYING) { >+ //safe clicked video as playing video and center it >+ videoId = evt.target.getVideoData().video_id; >+ if (this.playingVideos[videoId]) { >+ return; >+ } >+ this.playingVideos[videoId] = evt.target; >+ var index = this.videoIdToThumbIndex[videoId]; >+ if (index !== this.shownItemIndex) { >+ this.showThumb(index); >+ } >+ } else if (evt.data === YT.PlayerState.PAUSED || evt.data === YT.PlayerState.ENDED) { >+ //remove paused video from playing videos >+ videoId = evt.target.getVideoData().video_id; >+ delete this.playingVideos[videoId]; >+ } >+ }, >+ >+ //checks if all divs in the contentSlider are ready >+ thumbLoaded: function() { >+ this._loadedThumbsCount++; >+ if (this._loadedThumbsCount === this.preparedItems.length) { >+ this.onAllThumbsLoaded(); >+ } >+ }, >+ >+ onAllThumbsLoaded: function() { >+ this.allItemsLoaded = true; >+ >+ //calc offsets for all thumbs in the small view >+ this.defaultThumbOffsets = []; >+ var offset = 0; >+ for (var i = 0; i < this.itemNodes.length; i++) { >+ this.defaultThumbOffsets.push(offset); >+ offset += this.defaultThumbWidths[i]; >+ } >+ >+ this._handleFirstResize(); >+ }, >+ >+ //waits till the gallery is visible in the domTree >+ //can be cancelled with _stopFirstResize=true (added for use in TitlePane) >+ _handleFirstResize: function() { >+ //avoid the 200ms interval if possible >+ if (domGeometry.getMarginBox(this.domNode).w !== 0) { >+ this._handleResize(); >+ } else { >+ this._firstResizeInterval = setInterval(lang.hitch(this, function() { >+ if (this._stopFirstResize) { >+ clearInterval(this._firstResizeInterval); >+ } else if (domGeometry.getMarginBox(this.domNode).w !== 0) { >+ clearInterval(this._firstResizeInterval); >+ this._handleResize(); >+ } >+ }), 200); >+ } >+ }, >+ >+ _updateHeighestImage: function(img) { >+ if (img.naturalHeight > this.heighestImg.h) { >+ this.heighestImg.w = img.naturalWidth; >+ this.heighestImg.h = img.naturalHeight; >+ this.heighestImgRatio = img.naturalWidth / img.naturalHeight; >+ } >+ }, >+ >+ _updateWidestThumb: function(width) { >+ if (width > this.widestDefaultThumbWidth) { >+ this.widestDefaultThumbWidth = width; >+ } >+ }, >+ >+ resizeCarousel: function() { >+ if (domGeometry.getMarginBox(this.domNode).w === 0) { >+ return; >+ } >+ >+ //calc all values needed for toggling thumbsize and showing items >+ this._galleryWidth = domGeometry.getMarginBox(this.domNode).w; >+ this._leftNavButtonWidth = domGeometry.getMarginBox(this.leftButton).w; >+ this._rightNavButtonWidth = domGeometry.getMarginBox(this.rightButton).w; >+ this._widthForThumbs = this._galleryWidth - (this._leftNavButtonWidth + this._rightNavButtonWidth); >+ >+ this._totalWidthOfSmallThumbs = 0; >+ for (var i = 0; i < this.itemNodes.length; i++) { >+ thumbWidth = this.defaultThumbWidths[i]; >+ this._totalWidthOfSmallThumbs += thumbWidth; >+ } >+ >+ this._smallMaxOffset = Math.max(this._totalWidthOfSmallThumbs - this._widthForThumbs, 0); >+ this._bigThumbDimensions = this._getMaxWidthHeightForBigThumbs(); >+ var _bigContentSliderWidth = this.itemNodes.length * (this._bigThumbDimensions.maxWidthForThumb + this._galleryThumbMarginExtents); >+ this._bigMaxOffset = _bigContentSliderWidth - this._widthForThumbs; >+ this._smallViewHasNavButtons = this._totalWidthOfSmallThumbs > this._galleryWidth; >+ >+ >+ if (this.isBigThumbnails) { >+ this._scrollToTopOfGalleryWidget(); >+ } >+ >+ //reshow the current thumb with new dimensions >+ setTimeout(lang.hitch(this, function() { >+ this.showThumb(this.shownItemIndex); >+ }), 0); >+ }, >+ >+ _toggleNavButtonsVisibility: function(newOffset) { >+ if (this.isBigThumbnails || this._smallViewHasNavButtons) { >+ domClass.toggle(this.leftButton, 'disabled', (this.contentSliderOffset === 0 || this.shownItemIndex === 0)); >+ domClass.toggle(this.rightButton, 'disabled', ((this.isBigThumbnails && this.contentSliderOffset === this.defaultThumbOffsets[this.itemNodes.length-1]) || (!this.isBigThumbnails && this.contentSliderOffset === this._smallMaxOffset) || this.shownItemIndex === this.itemNodes.length - 1)); >+ } else { >+ domClass.add(this.leftButton, 'disabled'); >+ domClass.add(this.rightButton, 'disabled'); >+ } >+ }, >+ >+ showThumb: function(thumbIndex) { >+ if (thumbIndex < 0 || thumbIndex >= this.itemNodes.length) { >+ return; >+ } >+ >+ var newOffsetIgnoringNavButtons = 0; >+ var newOffsetWithNavButtons = 0; >+ >+ if (this.isBigThumbnails) { >+ ////for big thumbnails >+ this._hideVideosTemporarily(this._baseTransitionDuration + 50); >+ >+ var targetThumb = this.itemNodes[thumbIndex]; >+ >+ //revert previously enlarged thumb and enlarge new thumb >+ query('.galleryThumb.enlarged', this.contentSlider.domNode).style('width', '').style('height', '').removeClass('enlarged'); >+ ////_width >+ domStyle.set(targetThumb, 'width', lang.replace('{0}px', [this._bigThumbDimensions.maxWidthForThumb])); >+ ////_height >+ var targetThumbIsVideo = domClass.contains(targetThumb, 'galleryVideoThumb'); >+ var maxHeight = targetThumbIsVideo ? this._bigThumbDimensions.maxHeightForVideoThumb : this._bigThumbDimensions.maxHeightForImgThumb; >+ domClass.add(targetThumb, 'enlarged'); >+ domStyle.set(targetThumb, 'height', maxHeight + 'px'); >+ >+ //get new offset >+ newOffsetIgnoringNavButtons = this.defaultThumbOffsets[thumbIndex]; >+ newOffsetWithNavButtons = newOffsetIgnoringNavButtons - this._leftNavButtonWidth; >+ } else { >+ ////for small thumbnails >+ if (!this._smallViewHasNavButtons) { >+ newOffsetIgnoringNavButtons = -((this._widthForThumbs - this._totalWidthOfSmallThumbs) / 2) - domGeometry.getMarginBox(this.leftButton).w; >+ newOffsetWithNavButtons = newOffsetIgnoringNavButtons; >+ } else { >+ //offset for target thumb so that it is just visible >+ newOffsetIgnoringNavButtons = this.defaultThumbOffsets[thumbIndex]; >+ >+ //calc offset so that targetThumb is centered >+ var targetThumbWidth = this.defaultThumbWidths[thumbIndex]; >+ var newOffsetCentered = newOffsetIgnoringNavButtons - ((this._widthForThumbs - targetThumbWidth) / 2); >+ >+ //if the centered offset would show blank parts of the contentSlider revert to 0 or maxOffset >+ //if the centerd thumb would only be 50px away from 0 or maxOffset set them to 0 or maxOffset >+ if (newOffsetCentered <= (this._galleryThumbMarginExtents + 30) ) { >+ newOffsetIgnoringNavButtons = 0; >+ newOffsetWithNavButtons = newOffsetIgnoringNavButtons; >+ } else if (newOffsetCentered + (this._galleryThumbMarginExtents + 30) >= this._smallMaxOffset) { >+ newOffsetIgnoringNavButtons = this._smallMaxOffset; >+ newOffsetWithNavButtons = this._smallMaxOffset - this._leftNavButtonWidth - this._rightNavButtonWidth; >+ } else { >+ newOffsetIgnoringNavButtons = newOffsetCentered; >+ newOffsetWithNavButtons = newOffsetIgnoringNavButtons - this._leftNavButtonWidth; >+ } >+ } >+ } >+ >+ //set new offset and thumbIndex >+ this.shownItemIndex = thumbIndex || 0; >+ domStyle.set(this.contentSlider.domNode, 'transform', lang.replace('translate3d({0}px, 0, 0)', [(newOffsetWithNavButtons * (-1))])); >+ domStyle.set(this.contentSlider.domNode, '-webkit-transform', lang.replace('translate3d({0}px, 0, 0)', [(newOffsetWithNavButtons * (-1))])); >+ this.contentSliderOffset = newOffsetIgnoringNavButtons; >+ this._visibleOffset = newOffsetWithNavButtons; >+ >+ this._toggleNavButtonsVisibility(); >+ }, >+ >+ showNextThumbs: function() { >+ maxOffset = this.isBigThumbnails ? this._bigMaxOffset : this._smallMaxOffset; >+ if (this.contentSliderOffset === maxOffset || this.shownItemIndex === this.itemNodes.length - 1) { >+ return; >+ } >+ >+ //define functions >+ _calcCurrentFullyVisibleThumbs = lang.hitch(this, function() { >+ var lastFullyVisibleThumbIndex = 0; >+ var totalThumbsWidth = 0; >+ >+ var tmpWidth = 0; >+ var _widthForThumbs = this.shownItemIndex === 0 ? this._widthForThumbs + this._leftNavButtonWidth : this._widthForThumbs; >+ for (var tmpIndex = 0; tmpIndex <= this.itemNodes.length -1; ++tmpIndex) { >+ tmpWidth += this.defaultThumbWidths[tmpIndex]; >+ >+ isCurrentThumbFullyVisible = (tmpWidth - this._galleryThumbLeftRightMargin) <= (_widthForThumbs + this.contentSliderOffset); >+ if (!isCurrentThumbFullyVisible) { >+ break; >+ } >+ totalThumbsWidth = tmpWidth; >+ lastFullyVisibleThumbIndex = tmpIndex; >+ } >+ >+ return { >+ lastIndex: lastFullyVisibleThumbIndex, >+ width: totalThumbsWidth >+ }; >+ }); >+ >+ _calcNewFullyVisibleThumbs = lang.hitch(this, function(currThumbs) { >+ var lastFullyVisibleThumbIndex = currThumbs.lastIndex + 1; >+ var totalThumbsWidth = 0; >+ >+ var tmpWidth = 0; >+ var _widthForThumbs = this._widthForThumbs; >+ for (var tmpIndex = lastFullyVisibleThumbIndex; tmpIndex <= this.itemNodes.length -1; ++tmpIndex) { >+ tmpWidth += this.defaultThumbWidths[tmpIndex]; >+ >+ if (tmpIndex === this.itemNodes.length-1) { >+ _widthForThumbs += this._leftNavButtonWidth; >+ } >+ isCurrentThumbFullyVisible = tmpWidth < _widthForThumbs; >+ if (!isCurrentThumbFullyVisible) { >+ break; >+ } >+ totalThumbsWidth = tmpWidth; >+ lastFullyVisibleThumbIndex = tmpIndex; >+ } >+ >+ return { >+ lastIndex: lastFullyVisibleThumbIndex, >+ width: totalThumbsWidth >+ }; >+ }); >+ >+ _calcCenteringOffset = lang.hitch(this, function(currentThumbs, newThumbs) { >+ //calc new offset so that all new thumbs are centered >+ var offsetCentered = currentThumbs.width - ((this._widthForThumbs - newThumbs.width) / 2); >+ >+ //make sure to not exceed the maxOffset >+ var offset = Math.min(offsetCentered, maxOffset); >+ >+ return offset; >+ }); >+ >+ >+ //start >+ this.pauseAllVideos(); >+ >+ if (this.isBigThumbnails) { >+ ////for big thumbs >+ this.showThumb(this.shownItemIndex + 1); >+ } else { >+ ////for small thumbs >+ var newOffsetIgnoringNavButtons = 0; >+ var newIndex; >+ >+ //calc new offset and index >+ var isGalleryTooSmall = !this.isBigThumbnails && this.widestDefaultThumbWidth + this._galleryThumbMarginExtents >= this._widthForThumbs; >+ if (isGalleryTooSmall) { >+ newIndex = this.shownItemIndex + 1; >+ var thumbOffset = this.defaultThumbOffsets[newIndex]; >+ newOffsetIgnoringNavButtons = Math.min(thumbOffset, this._smallMaxOffset); >+ } else { >+ var isCurrentThumbFullyVisible; >+ var currentFullyVisibleThumbs = _calcCurrentFullyVisibleThumbs(); >+ var newFullyVisibleThumbs = _calcNewFullyVisibleThumbs(currentFullyVisibleThumbs); >+ >+ newOffsetIgnoringNavButtons = _calcCenteringOffset(currentFullyVisibleThumbs, newFullyVisibleThumbs); >+ newIndex = newFullyVisibleThumbs.lastIndex; >+ } >+ >+ //set the new offset and index >+ var newOffsetWithNavButtons = newIndex === this.itemNodes.length -1 ? newOffsetIgnoringNavButtons - ( this._leftNavButtonWidth * 2) : newOffsetIgnoringNavButtons - this._leftNavButtonWidth; >+ var _oldOffset = this._visibleOffset; >+ >+ //set transition duration based on distance >+ this._setSliderTransitionDuration(newOffsetWithNavButtons, _oldOffset); >+ >+ domStyle.set(this.contentSlider.domNode, 'transform', lang.replace('translate3d({0}px, 0, 0)', [newOffsetWithNavButtons * (-1)])); >+ domStyle.set(this.contentSlider.domNode, '-webkit-transform', lang.replace('translate3d({0}px, 0, 0)', [(newOffsetWithNavButtons * (-1))])); >+ this.contentSliderOffset = newOffsetIgnoringNavButtons; >+ this._visibleOffset = newOffsetWithNavButtons; >+ this.shownItemIndex = newIndex; >+ >+ this._toggleNavButtonsVisibility(); >+ } >+ }, >+ >+ showPrevThumbs: function() { >+ if (this.contentSliderOffset === 0 || this.shownItemIndex === 0) { >+ return; >+ } >+ >+ //define functions >+ var _findFirstFullyVisibleThumb = lang.hitch(this, function() { >+ var totalWidth = 0; >+ for (var ithumb = 0; ithumb <= this.itemNodes.length -1; ++ithumb) { >+ totalWidth += this.defaultThumbWidths[ithumb]; >+ >+ var isThumbFullyVisible = totalWidth - this.contentSliderOffset >= this.defaultThumbWidths[ithumb] - this._galleryThumbMarginExtents; >+ if (isThumbFullyVisible) { >+ break; >+ } >+ } >+ return ithumb; >+ }); >+ >+ var _findNextFullyVisibleThumbs = lang.hitch(this, function(ifirstThumb) { >+ var firstFullyVisibleThumbIndex = ifirstThumb -1; >+ var totalThumbsWidth = 0; >+ >+ var tmpWidth = 0; >+ var _widthForThumbs = this._widthForThumbs; >+ for (var ithumb = firstFullyVisibleThumbIndex; ithumb >= 0; --ithumb) { >+ tmpWidth += this.defaultThumbWidths[ithumb]; >+ >+ if (ithumb === 0) { >+ _widthForThumbs += this._leftNavButtonWidth; >+ } >+ isCurrentThumbFullyVisible = tmpWidth < _widthForThumbs; >+ if (!isCurrentThumbFullyVisible) { >+ break; >+ } >+ totalThumbsWidth = tmpWidth; >+ firstFullyVisibleThumbIndex = ithumb; >+ } >+ return { >+ width: totalThumbsWidth, >+ firstIndex: firstFullyVisibleThumbIndex >+ }; >+ }); >+ >+ var _calcCenteringOffset = lang.hitch(this, function(newThumbs) { >+ var offsetUntilNewThumbs = this.defaultThumbOffsets[newThumbs.firstIndex]; >+ var newOffsetCentered = offsetUntilNewThumbs - ((this._widthForThumbs - newThumbs.width) / 2); >+ >+ //make sure to not go lower than 0 >+ return Math.max(newOffsetCentered, 0); >+ }); >+ >+ >+ //start >+ this.pauseAllVideos(); >+ >+ if (this.isBigThumbnails) { >+ this.showThumb(this.shownItemIndex - 1); >+ } else { >+ ////for small thumbs >+ var newOffsetIgnoringNavButtons; >+ var newIndex; >+ >+ //calc new offset and index >+ var isGalleryTooSmall = !this.isBigThumbnails && this.widestDefaultThumbWidth + this._galleryThumbMarginExtents >= this._widthForThumbs; >+ if (isGalleryTooSmall) { >+ newIndex = this.shownItemIndex-1; >+ newOffsetIgnoringNavButtons = this.defaultThumbOffsets[newIndex]; >+ } else { >+ var isCurrentThumbFullyVisible; >+ var currFirstFullyVisibleThumbIndex = _findFirstFullyVisibleThumb(); >+ var newFullyVisibleThumbs = _findNextFullyVisibleThumbs(currFirstFullyVisibleThumbIndex); >+ >+ newOffsetIgnoringNavButtons = _calcCenteringOffset(newFullyVisibleThumbs); >+ newIndex = newFullyVisibleThumbs.firstIndex; >+ } >+ >+ //set the new offset and index >+ var newOffsetWithNavButtons = newIndex === 0 ? newOffsetIgnoringNavButtons : newOffsetIgnoringNavButtons - this._leftNavButtonWidth; >+ var _oldOffset = this._visibleOffset; >+ >+ //set transition duration based on distance >+ this._setSliderTransitionDuration(newOffsetWithNavButtons, _oldOffset); >+ >+ domStyle.set(this.contentSlider.domNode, 'transform', lang.replace('translate3d({0}px, 0, 0)', [(newOffsetWithNavButtons * (-1))])); >+ domStyle.set(this.contentSlider.domNode, '-webkit-transform', lang.replace('translate3d({0}px, 0, 0)', [(newOffsetWithNavButtons * (-1))])); >+ this.contentSliderOffset = newOffsetIgnoringNavButtons; >+ this._visibleOffset = newOffsetWithNavButtons; >+ this.shownItemIndex = newIndex; >+ >+ this._toggleNavButtonsVisibility(); >+ } >+ }, >+ >+ _setSliderTransitionDuration: function(newOffset, oldOffset) { >+ var offsetDistance = Math.abs(oldOffset - newOffset); >+ var isNewTransitionDuration = offsetDistance > this._baseTransitionDuration; >+ if (isNewTransitionDuration) { >+ domStyle.set(this.contentSlider.domNode, 'transition-duration', lang.replace('{0}ms', [offsetDistance])); >+ setTimeout(lang.hitch(this, function() { >+ domStyle.set(this.contentSlider.domNode, 'transition-duration', ''); >+ }), offsetDistance); >+ } >+ }, >+ >+ _hideVideosTemporarily: function(duration) { >+ //hide loaded youtube iframes during resize for performance reasons >+ query('.galleryVideoThumb.loaded .galleryVideoThumbnailWrapper', this.contentSlider.domNode).removeClass('dijitHidden'); >+ query('.galleryVideoThumb.loaded .galleryVideo', this.contentSlider.domNode).addClass('dijitHidden'); >+ setTimeout(lang.hitch(this, function() { >+ query('.galleryVideoThumb.loaded .galleryVideo', this.contentSlider.domNode).removeClass('dijitHidden'); >+ query('.galleryVideoThumb.loaded .galleryVideoThumbnailWrapper', this.contentSlider.domNode).addClass('dijitHidden'); >+ }), duration); >+ }, >+ >+ toggleThumbSize: function(newIndex) { >+ newIndex = (newIndex === undefined) ? this.shownItemIndex : newIndex; >+ >+ if (this.isBigThumbnails) { >+ this._toggleToSmallThumbs(); >+ } else { >+ this._toggleToBigThumbs(newIndex); >+ } >+ domClass.toggle(this.scaleButton, 'minimize'); >+ >+ this.isBigThumbnails = !this.isBigThumbnails; >+ this.showThumb(newIndex); >+ }, >+ >+ _toggleToSmallThumbs: function() { >+ this._hideVideosTemporarily(this._baseTransitionDuration + 50); >+ //remove height and width for thumbs and navButtons >+ query('.galleryNavButton', this.outerContainer.domNode).style('height', ''); >+ query('.galleryThumb', this.contentSlider.domNode).style('width', '').style('height', ''); >+ }, >+ >+ _toggleToBigThumbs: function(newIndex) { >+ this.pauseAllVideos(newIndex); >+ >+ this._scrollToTopOfGalleryWidget(); >+ >+ //enlarge navButtons and VerticalAlignHelperThumb >+ var maxHeight = Math.max(this._bigThumbDimensions.maxHeightForImgThumb, this._bigThumbDimensions.maxHeightForVideoThumb); >+ query('.galleryNavButton', this.outerContainer.domNode).style('height', lang.replace('{0}px', [maxHeight])); >+ domStyle.set(this.galleryThumbVerticalAlignHelper, 'height', lang.replace('{0}px', [maxHeight])); >+ }, >+ >+ _scrollToTopOfGalleryWidget: function() { >+ //##scroll to the top of the galleryWidget >+ var scrollTarget = domGeometry.position(this.domNode, true).y - 50; >+ var scrollInterval = setInterval(lang.hitch(this, function() { >+ window.scrollTo(0, scrollTarget); >+ }), 1); >+ >+ //wait for the transition to finish >+ setTimeout(function() { >+ clearInterval(scrollInterval); >+ }, this._baseTransitionDuration + 100); >+ }, >+ >+ _getMaxWidthHeightForBigThumbs: function() { >+ //##get max width for a big thumb >+ var maxWidthForThumb = this._widthForThumbs - this._galleryThumbMarginExtents; >+ >+ //##get the max height for a big thumb >+ var maxHeight = dojo.window.getBox().h - 100; >+ maxHeight = (maxHeight < this.defaultThumbHeight) ? this.defaultThumbHeight : maxHeight; >+ var maxHeightForImgThumb = Math.min(maxWidthForThumb / this.heighestImgRatio, maxHeight, this.heighestImg.h); >+ var maxHeightForVideoThumb = maxWidthForThumb / (this._youtubeIframeRatio); >+ >+ return { >+ maxWidthForThumb: maxWidthForThumb, >+ maxHeightForImgThumb: maxHeightForImgThumb, >+ maxHeightForVideoThumb: maxHeightForVideoThumb >+ }; >+ }, >+ >+ _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._removeLoadingScreen(); >+ }), 200); >+ >+ this._resizeDeferred.otherwise(function() { /* prevent logging of exception */ }); >+ }, >+ >+ _removeLoadingScreen: function() { >+ if (!this.loaded) { >+ //fade the loadingAnimationOverlay out over given transition duration >+ var transitionDuration = 600; >+ domStyle.set(this.galleryLoadingOverlay, 'transition', lang.replace('opacity {0}ms', [transitionDuration])); >+ domClass.add(this.galleryLoadingOverlay, 'loaded'); >+ domClass.add(this.contentSlider.domNode, 'noTransition'); >+ domStyle.set(this.contentSlider.domNode, 'transform', lang.replace('translate3d({0}px, 0, 0)', [this._leftNavButtonWidth])); >+ domStyle.set(this.contentSlider.domNode, '-webkit-transform', lang.replace('translate3d({0}px, 0, 0)', [this._leftNavButtonWidth])); >+ >+ //hide the loading overlay after transition duration >+ tools.defer(lang.hitch(this, function() { >+ domClass.add(this.galleryLoadingOverlay, 'dijitHidden'); >+ domClass.remove(this.contentSlider.domNode, 'noTransition'); >+ }), transitionDuration); >+ >+ //remove styles needed for loading overlay >+ domStyle.set(this.domNode, 'height', ''); >+ domStyle.set(this.domNode, 'overflow', ''); >+ >+ domClass.remove(this.scaleButton, 'dijitHidden'); >+ this.loaded = true; >+ } >+ }, >+ >+ startup: function() { >+ this.inherited(arguments); >+ this.own(on(baseWin.doc, 'resize', lang.hitch(this, '_handleResize'))); >+ this.own(on(kernel.global, 'resize', lang.hitch(this, '_handleResize'))); >+ }, >+ >+ destroy: function() { >+ this.inherited(arguments); >+ >+ //remove all inserted CssRules >+ array.forEach(this._insertedCssRules, function(rule) { >+ styles.removeCssRule(rule.selector, rule.declaration); >+ }); >+ }, >+ >+ pauseAllVideos: function(pauseExceptionIndex) { >+ if (Object.keys(this.playingVideos).length === 0) { >+ return; >+ } >+ >+ //pause all playing videos >+ //if a pauseExceptionIndex is given do not pause that video if it is playing >+ tools.forIn(this.playingVideos, lang.hitch(this, function(_videoId, player) { >+ if (this.videoIdToThumbIndex[_videoId] !== pauseExceptionIndex) { >+ player.pauseVideo(); >+ } >+ })); >+ }, >+ }); >+}); >Index: umc/js/appcenter/thumbnailError.svg >=================================================================== >--- umc/js/appcenter/thumbnailError.svg (Revision 0) >+++ umc/js/appcenter/thumbnailError.svg (Arbeitskopie) >@@ -0,0 +1 @@ >+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M16.142 2L22 7.858v8.284L16.142 22H7.858L2 16.142V7.858L7.858 2h8.284zm.83-2H7.028L0 7.03v9.94L7.03 24h9.94L24 16.97V7.03L16.97 0zM11 6h2v8h-2V6zm1 12.25a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5z"/></svg> >\ No newline at end of file >Index: umc/js/appcenter/videoPlayButton.svg >=================================================================== >--- umc/js/appcenter/videoPlayButton.svg (Revision 0) >+++ umc/js/appcenter/videoPlayButton.svg (Arbeitskopie) >@@ -0,0 +1,63 @@ >+<?xml version="1.0" encoding="UTF-8" standalone="no"?> >+<svg >+ xmlns:dc="http://purl.org/dc/elements/1.1/" >+ xmlns:cc="http://creativecommons.org/ns#" >+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >+ xmlns:svg="http://www.w3.org/2000/svg" >+ xmlns="http://www.w3.org/2000/svg" >+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" >+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" >+ width="24" >+ height="24" >+ viewBox="0 0 24 24" >+ id="svg2" >+ version="1.1" >+ inkscape:version="0.48.4 r9939" >+ sodipodi:docname="iconmonstr-video-15.svg"> >+ <metadata >+ id="metadata10"> >+ <rdf:RDF> >+ <cc:Work >+ rdf:about=""> >+ <dc:format>image/svg+xml</dc:format> >+ <dc:type >+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> >+ <dc:title></dc:title> >+ </cc:Work> >+ </rdf:RDF> >+ </metadata> >+ <defs >+ id="defs8" /> >+ <sodipodi:namedview >+ pagecolor="#ffffff" >+ bordercolor="#666666" >+ borderopacity="1" >+ objecttolerance="10" >+ gridtolerance="10" >+ guidetolerance="10" >+ inkscape:pageopacity="0" >+ inkscape:pageshadow="2" >+ inkscape:window-width="1920" >+ inkscape:window-height="1025" >+ id="namedview6" >+ showgrid="false" >+ inkscape:zoom="9.8333333" >+ inkscape:cx="-8.644706" >+ inkscape:cy="11.996192" >+ inkscape:window-x="-2" >+ inkscape:window-y="-3" >+ inkscape:window-maximized="1" >+ inkscape:current-layer="svg2" /> >+ <path >+ d="M 12,0 C 5.373,0 0,5.373 0,12 0,18.627 5.373,24 12,24 18.627,24 24,18.627 24,12 24,5.373 18.627,0 12,0 z" >+ id="path4" >+ style="fill:#353535;stroke:none;fill-opacity:1" >+ inkscape:connector-curvature="0" >+ sodipodi:nodetypes="sssss" /> >+ <path >+ inkscape:connector-curvature="0" >+ d="M 9,17 9,7 18,12.146 z" >+ id="path4-1" >+ style="fill:#ffffff;stroke:none" >+ sodipodi:nodetypes="cccc" /> >+</svg> >Index: umc/js/appcenter.styl >=================================================================== >--- umc/js/appcenter.styl (Revision 67996) >+++ umc/js/appcenter.styl (Arbeitskopie) >@@ -445,61 +445,116 @@ > @media screen and (max-width: 549px) > width: 100% > >- .umcCarouselWidget >+ .umcThumbnailGallery > position: relative >+ line-height: 0 > >- .carouselOuterContainer >- margin: auto >+ .galleryLoadingOverlay >+ position: absolute >+ width: 100% >+ height: 100% >+ z-index: 1 >+ background-image: url(../../dijit/themes/umc/images/standbyAnimation.svg) >+ background-repeat: no-repeat >+ background-position: center center >+ background-color: #f0f0f0 >+ opacity: 1 >+ >+ &.loaded >+ opacity: 0 >+ pointer-events: none >+ >+ .galleryOuterContainer > position: relative >- transition: height 0.5s > > .contentSliderWrapper >- float: left >+ display: inline-block >+ > white-space: nowrap > overflow: hidden >- position: relative >- height: 100% > >+ width: 100% > .contentSlider >- position: absolute >- left: 0 >- transition: left 0.5s >+ display: inline-block >+ transform: translate3d(0, 0, 0) >+ transition-property: transform > >- div >- margin: 0 10px >+ &.noTransition >+ transition: none >+ >+ .galleryThumb > display: inline-block >- /*border: 2px solid darkgrey;*/ >- /*box-sizing: content-box;*/ >+ vertical-align: middle >+ transition-property: width, height > >+ &.galleryImgThumb >+ background-size: contain >+ background-position: center center >+ background-repeat: no-repeat >+ cursor: pointer > >- &.noTransition >- transition: none !important >+ &.brokenImg >+ width: 150px >+ box-shadow: inset 0px 0px 6px #5a5a5a >+ background: url("appcenter/thumbnailError.svg") no-repeat, #e6e6e6 >+ background-position: center center >+ background-size: 30% auto > >- .carouselScreenshot >- cursor: pointer >- display: block >- margin: auto >+ &.verticalAlignHelper >+ margin: 0 !important >+ height: 0 >+ >+ .galleryVideoThumb > position: relative >- top: 50% >- transform: translateY(-50%) >- -ms-transform: translateY(-50%) >- -webkit-transform: translateY(-50%) >- transition: max-height 0.5s, max-width 0.5s > >- .carouselButton >- float: left >+ .galleryVideo >+ width: 100% >+ height: 100% >+ background-color: black > >+ .galleryVideoThumbnailWrapper >+ width: 100% >+ height: 100% >+ >+ .galleryVideoThumbnail >+ width: 100% >+ height: 100% >+ background-size: cover >+ background-position: center center >+ background-repeat: no-repeat >+ cursor: pointer >+ >+ .galleryVideoPlayButtonIcon >+ width: 100% >+ height: 100% >+ background: url("appcenter/videoPlayButton.svg") no-repeat; >+ background-size: auto 30% >+ background-position: center center >+ position: absolute >+ top: 0 >+ >+ &:after >+ content: '' >+ height: 100% >+ display: inline-block >+ vertical-align: middle >+ >+ .galleryNavButton > cursor: pointer > width: 40px >- height: 100% > opacity: 1 >- transition: opacity 0.5s >+ transition-property: opacity, height >+ position: absolute >+ z-index: 1 >+ background-color: #f0f0f0 > > &.disabled > opacity: 0 > cursor: default >+ pointer-events: none >+ height: 0 > >- .carouselButtonImage >+ .galleryNavButtonImage > background-image: url("appcenter/carouselArrowRight.svg") > background-size: contain > background-repeat: no-repeat >@@ -511,13 +566,15 @@ > &:hover > opacity: 1 > >- &.rightCarouselButton >+ &.rightGalleryNavButton > margin-left: 5px >+ right: 0 >+ top: 0 > >- &.leftCarouselButton >+ &.leftGalleryNavButton > margin-right: 5px > >- .carouselButtonImage >+ .galleryNavButtonImage > transform: rotateY(180deg) > -ms-transform: rotateY(180deg) > -webkit-transform: rotateY(180deg)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
Attachments on
bug 39794
:
7446
| 7523