From 225d1513428af28854eb4c039468f2d866eee730 Mon Sep 17 00:00:00 2001 From: jbtbnl Date: Sat, 22 Mar 2014 18:55:49 +0100 Subject: [PATCH 1/5] Work in progress for seamless layout --- .gitignore | 50 +++++++++++++++++++++++++++++++++++++ css/styles.css | 14 ++++++----- index.php | 2 ++ js/gallery.js | 22 ++++++++++++---- js/seamlessgallery.js | 58 +++++++++++++++++++++++++++++++++++++++++++ js/seamlessimage.js | 46 ++++++++++++++++++++++++++++++++++ 6 files changed, 181 insertions(+), 11 deletions(-) create mode 100644 .gitignore create mode 100644 js/seamlessgallery.js create mode 100644 js/seamlessimage.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b0e4a7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# just sane ignores +.*.sw[po] +*.bak +*.BAK +*~ +*.orig +*.class +.cvsignore +Thumbs.db +*.py[co] +_darcs/* +CVS/* +.svn/* +RCS/* +*.backup* + +# kdevelop +.kdev +*.kdev4 +*.kate-swp + +# kate editor +.kateproject* + +# Lokalize +*lokalize* + +# eclipse +.project +.settings + +# netbeans +nbproject + +# phpStorm +.idea +*.iml + +# geany +*.geany + +# Cloud9IDE +.settings.xml +.c9revisions + +# vim ex mode +.vimrc + +# Mac OS +.DS_Store diff --git a/css/styles.css b/css/styles.css index cdacb78..c92b172 100644 --- a/css/styles.css +++ b/css/styles.css @@ -2,10 +2,14 @@ button.share { display: none; } -#gallery { - overflow: auto; - overflow-x: hidden; - text-align: justify; +#gallery .row { + line-height: 0; +} + +#gallery .row a { + display: inline-block; + height: auto; + padding: 1px; } #gallery > a.album { @@ -78,8 +82,6 @@ button.share { #gallery > a { display: inline-block; - height: 200px; - margin: 1em; position: relative; vertical-align: top; *display: inline; diff --git a/index.php b/index.php index 5a9f6a0..e49ea8d 100644 --- a/index.php +++ b/index.php @@ -10,6 +10,8 @@ OCP\App::checkAppEnabled('gallery'); OCP\App::setActiveNavigationEntry('gallery_index'); +OCP\Util::addScript('gallery', 'seamlessimage'); +OCP\Util::addScript('gallery', 'seamlessgallery'); OCP\Util::addScript('gallery', 'gallery'); OCP\Util::addScript('gallery', 'thumbnail'); OCP\Util::addStyle('gallery', 'styles'); diff --git a/js/gallery.js b/js/gallery.js index 5d60943..bbe2c31 100644 --- a/js/gallery.js +++ b/js/gallery.js @@ -5,6 +5,19 @@ Gallery.currentAlbum = ''; Gallery.subAlbums = {}; Gallery.users = []; Gallery.displayNames = []; +Gallery.seamlessGallery = new SeamlessGallery('#gallery', 150); +Gallery.resizeTriggered = false; + +$(window).resize(function() { + if(!Gallery.resizeTriggered) { + Gallery.resizeTriggered = true; + var delay = setInterval(function() { + Gallery.seamlessGallery.redraw(); + clearInterval(delay); + Gallery.resizeTriggered = false; + }, 500); + } +}); Gallery.sortFunction = function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); @@ -135,13 +148,13 @@ Gallery.view = {}; Gallery.view.element = null; Gallery.view.clear = function () { Gallery.view.element.empty(); + $(gallery).css('width', $(gallery).parent().width()); }; Gallery.view.cache = {}; Gallery.view.addImage = function (image) { var link , thumb; if (Gallery.view.cache[image]) { - Gallery.view.element.append(Gallery.view.cache[image]); thumb = Thumbnail.get(image); thumb.queue(); } else { @@ -153,10 +166,12 @@ Gallery.view.addImage = function (image) { thumb = Thumbnail.get(image); thumb.queue().then(function (thumb) { link.removeClass('loading'); + Gallery.seamlessGallery.add( + new SeamlessImage(thumb, link.attr('data-path'), link.attr('href'), '') + ); link.append(thumb); }); - Gallery.view.element.append(link); Gallery.view.cache[image] = link; } }; @@ -265,7 +280,6 @@ Gallery.view.viewAlbum = function (albumPath) { if (subAlbums) { for (i = 0; i < subAlbums.length; i++) { Gallery.view.addAlbum(subAlbums[i]); - Gallery.view.element.append(' '); //add a space for justify } } @@ -273,7 +287,6 @@ Gallery.view.viewAlbum = function (albumPath) { if (album) { for (i = 0; i < album.length; i++) { Gallery.view.addImage(album[i]); - Gallery.view.element.append(' '); //add a space for justify } } @@ -333,7 +346,6 @@ Gallery.view.showUsers = function () { album = subAlbums[j]; album = Gallery.subAlbums[album][0];//first level sub albums is share source id Gallery.view.addAlbum(album); - Gallery.view.element.append(' '); //add a space for justify } } } diff --git a/js/seamlessgallery.js b/js/seamlessgallery.js new file mode 100644 index 0000000..b11042a --- /dev/null +++ b/js/seamlessgallery.js @@ -0,0 +1,58 @@ +/* Copyright (c) 2014, Jan ten Bokkel + * This file is licensed under the Affero General Public License version 3 + * or later. See the COPYING-README file. */ + +function SeamlessGallery(gallery, lineHeight) { + this.gallery = gallery; + this.lineHeight = lineHeight; + this.images = new Array(); + this.currentElement = 0; +} + +SeamlessGallery.prototype.queueRowWidth = function() { + var width = 0; + var i = 0; + for(i = this.currentElement; i < this.images.length; i++) { + width += this.images[i].width(); + if(width >= $(this.gallery).width()) break; + } + return (width < $(this.gallery).width()) ? false : (width - this.images[i].width()); +}; + +SeamlessGallery.prototype.queueRowElements = function() { + var width = 0; + var i = 0; + for(i = this.currentElement; i < this.images.length; i++) { + width += this.images[i].width(); + if(width >= $(this.gallery).width()) break; + } + return (width < $(this.gallery).width()) ? false : (i-this.currentElement); +}; + +SeamlessGallery.prototype.add = function(seamlessImage) { + seamlessImage.scaleToHeight(this.lineHeight); + this.images.push(seamlessImage); + this.draw(); +}; + +SeamlessGallery.prototype.draw = function() { + + while(this.queueRowElements()) { + // Queue width exceeds gallery width so let's render the next line + scale = $(this.gallery).width() / this.queueRowWidth(); + var row = $('
'); + row.addClass('row'); + for(var i = 0; i < this.queueRowElements(); i++) { + row.append(this.images[this.currentElement + i].render(scale)); + } + $(this.gallery).append(row); + this.currentElement += this.queueRowElements(); + } +}; + +SeamlessGallery.prototype.redraw = function() { + $(this.gallery).css('width', $(this.gallery).parent().width()); + $(this.gallery).empty(); + this.currentElement = 0; + this.draw(); +}; \ No newline at end of file diff --git a/js/seamlessimage.js b/js/seamlessimage.js new file mode 100644 index 0000000..5df7293 --- /dev/null +++ b/js/seamlessimage.js @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, Jan ten Bokkel + * This file is licensed under the Affero General Public License version 3 + * or later. See the COPYING-README file. */ + +function SeamlessImage(image, dataPath, href, name) { + this.image = image; + this.dataPath = dataPath; + this.href = href; + this.name = name; + this._height = image.height; + this._width = image.width; + this.padding = 1; +} + +SeamlessImage.prototype.render = function(scale) { + link = $(''); + link.attr('data-path', this.dataPath); + link.attr('href', this.href); + link.css('height', (Math.floor(this.height() * scale * 10) / 10) - this.padding*2); + link.css('width', (Math.floor(this.width() * scale * 10) / 10) - this.padding*2); + image = $(this.image); + image.css('height', (Math.floor(this.height() * scale * 10) / 10) - this.padding*2); + image.css('width', (Math.floor(this.width() * scale * 10) / 10) - this.padding*2); + link.append(image); + return link; +}; + +SeamlessImage.prototype.scaleToHeight = function(height) { + var factor = height / this.image.height; + this._height = this.image.height * factor; + this._width = this.image.width * factor; +}; + +SeamlessImage.prototype.scaleToWidth = function(width) { + var factor = width / this.image.width; + this._height = this.image.height * factor; + this._width = this.image.width * factor; +}; + +SeamlessImage.prototype.width = function() { + return this._width; +}; + +SeamlessImage.prototype.height = function() { + return this._height; +}; \ No newline at end of file From 68d9c36ff7c23b5727f99e99c523d8c9025c3e32 Mon Sep 17 00:00:00 2001 From: jbtbnl Date: Mon, 24 Mar 2014 18:52:21 +0100 Subject: [PATCH 2/5] Fixes various issues with loading images into seamless gallery, fixes slideshow and fixes last row of images not showing. --- ajax/getimages.php | 20 +++++++++++++++--- css/styles.css | 8 ++++++++ js/gallery.js | 37 +++++++++++---------------------- js/seamlessgallery.js | 48 +++++++++++++++++++++++++++++-------------- js/seamlessimage.js | 5 +++-- js/thumbnail.js | 8 +++++++- templates/index.php | 1 + 7 files changed, 81 insertions(+), 46 deletions(-) diff --git a/ajax/getimages.php b/ajax/getimages.php index 20e1b13..cb2bb50 100644 --- a/ajax/getimages.php +++ b/ajax/getimages.php @@ -30,14 +30,17 @@ $view = new \OC\Files\View(\OC\Files\Filesystem::getView()->getAbsolutePath($path)); $images = $view->searchByMime('image'); - + + $dimensions = array(); $result = array(); foreach ($images as $image) { $result[] = $token . $image['path']; + $img = new OCP\Image($token . $image['path']); + $dimensions[] = array('height' => $img->height(), 'width' => $img.width()); } OCP\JSON::setContentTypeHeader(); - echo json_encode(array('images' => $result, 'users' => array(), 'displayNames' => array())); + echo json_encode(array('images' => $result, 'users' => array(), 'displayNames' => array(), 'dimensions' => $dimensions)); exit; } @@ -48,7 +51,9 @@ $images = \OCP\Files::searchByMime('image'); $user = \OCP\User::getUser(); +$ownerView = new \OC\Files\View('/' . $user . '/files'); +$dimensions = array(); foreach ($images as &$image) { // we show shared images another way if (substr($image['path'], 0, 8) === '/Shared/') { @@ -58,6 +63,13 @@ if (strpos($path, DIRECTORY_SEPARATOR . ".")) { continue; } + +// $local = $ownerView->getLocalFile($image['path']); +// $img = new OCP\Image($local); +// if($img != false) { +// $dimensions[] = array('height' => $img->height(), 'width' => $img->width()); +// } + //$dimensions[] = '/' . $user . '/files/' . $local; $image['path'] = $user . $image['path']; } @@ -103,7 +115,9 @@ function startsWith($haystack, $needle) { $result = array(); foreach ($images as $image) { $result[] = $image['path']; + //$img = new OCP\Image($image['path']); + //$dimensions[] = array('height' => $img->height(), 'width' => $img.width()); } OCP\JSON::setContentTypeHeader(); -echo json_encode(array('images' => $result, 'users' => $users, 'displayNames' => $displayNames)); +echo json_encode(array('images' => $result, 'users' => $users, 'displayNames' => $displayNames, 'dimensions' => $dimensions)); diff --git a/css/styles.css b/css/styles.css index c92b172..fba457c 100644 --- a/css/styles.css +++ b/css/styles.css @@ -2,6 +2,14 @@ button.share { display: none; } +#loading { + height: 100px; + width: 100%; + padding-top: 45px; + z-index: 10; + background-color: rgba(255,255,255,0.3); +} + #gallery .row { line-height: 0; } diff --git a/js/gallery.js b/js/gallery.js index bbe2c31..dbb3eda 100644 --- a/js/gallery.js +++ b/js/gallery.js @@ -147,32 +147,27 @@ Gallery.share = function (event) { Gallery.view = {}; Gallery.view.element = null; Gallery.view.clear = function () { + Thumbnail.clearQueue(); + Gallery.seamlessGallery.clear(); Gallery.view.element.empty(); $(gallery).css('width', $(gallery).parent().width()); }; Gallery.view.cache = {}; Gallery.view.addImage = function (image) { - var link , thumb; + var thumb; if (Gallery.view.cache[image]) { - thumb = Thumbnail.get(image); - thumb.queue(); + Gallery.seamlessGallery.add(Gallery.view.cache[image]); } else { - link = $(''); - link.addClass('image loading'); - link.attr('data-path', image); - link.attr('href', Gallery.getImage(image)).attr('rel', 'album').attr('alt', OC.basename(image)).attr('title', OC.basename(image)); - + Gallery.view.cache[image] = null; thumb = Thumbnail.get(image); thumb.queue().then(function (thumb) { - link.removeClass('loading'); - Gallery.seamlessGallery.add( - new SeamlessImage(thumb, link.attr('data-path'), link.attr('href'), '') - ); - link.append(thumb); + if($.inArray(image, Gallery.albums[Gallery.currentAlbum]) === -1) return; // filter out images removed from queue but already loading + var seamlessImage = new SeamlessImage(thumb, image, Gallery.getImage(image), ''); + Gallery.seamlessGallery.add(seamlessImage); + Gallery.view.cache[image] = seamlessImage; }); - Gallery.view.cache[image] = link; } }; @@ -183,9 +178,6 @@ Gallery.view.addAlbum = function (path, name) { thumbs = Gallery.view.addAlbum.thumbs[path]; Gallery.view.element.append(Gallery.view.cache[path]); //event handlers are removed when using clear() - Gallery.view.cache[path].click(function () { - Gallery.view.viewAlbum(path); - }); Gallery.view.cache[path].mousemove(function (event) { Gallery.view.addAlbum.mouseEvent.call(Gallery.view.cache[path], thumbs, event); }); @@ -198,9 +190,6 @@ Gallery.view.addAlbum = function (path, name) { label = $('
'); - row.addClass('row'); - for(var i = 0; i < this.queueRowElements(); i++) { - row.append(this.images[this.currentElement + i].render(scale)); - } - $(this.gallery).append(row); - this.currentElement += this.queueRowElements(); + // Draw rows + this.drawRow(this.currentElement, this.currentElement+this.queueRowElements()); + } + if((this.length === this.images.length) && (this.currentElement < this.images.length)) { + // Draw last row + this.drawRow(this.currentElement, this.images.length, true); + $('#loading').hide(); } }; +SeamlessGallery.prototype.drawRow = function(start, end, lastRow) { + var scale = $(this.gallery).width() / this.queueRowWidth(start, end); + if(lastRow === true) scale = Math.min(scale, this.maxScaleLastRow); + var row = $('
'); + row.addClass('row'); + for(var i = start; i < end; i++) { + row.append(this.images[i].render(scale)).fadeTo(this.fadeInTime, 1); + } + $(this.gallery).append(row); + this.currentElement += end - start; +}; + SeamlessGallery.prototype.redraw = function() { $(this.gallery).css('width', $(this.gallery).parent().width()); $(this.gallery).empty(); this.currentElement = 0; this.draw(); +}; + +SeamlessGallery.prototype.clear = function() { + this.images = new Array(); + this.currentElement = 0; }; \ No newline at end of file diff --git a/js/seamlessimage.js b/js/seamlessimage.js index 5df7293..c956623 100644 --- a/js/seamlessimage.js +++ b/js/seamlessimage.js @@ -13,12 +13,13 @@ function SeamlessImage(image, dataPath, href, name) { } SeamlessImage.prototype.render = function(scale) { - link = $(''); + var link = $(''); + link.addClass('image'); link.attr('data-path', this.dataPath); link.attr('href', this.href); link.css('height', (Math.floor(this.height() * scale * 10) / 10) - this.padding*2); link.css('width', (Math.floor(this.width() * scale * 10) / 10) - this.padding*2); - image = $(this.image); + var image = $(this.image); image.css('height', (Math.floor(this.height() * scale * 10) / 10) - this.padding*2); image.css('width', (Math.floor(this.width() * scale * 10) / 10) - this.padding*2); link.append(image); diff --git a/js/thumbnail.js b/js/thumbnail.js index 8952f56..acbcd9f 100644 --- a/js/thumbnail.js +++ b/js/thumbnail.js @@ -25,6 +25,12 @@ Thumbnail.getUrl = function (path, square) { } }; +Thumbnail.clearQueue = function() { + Thumbnail.queue = Array(); + Thumbnail.map = {}; + Thumbnail.squareMap = {}; +}; + Thumbnail.prototype.load = function () { var that = this; if (!this.image) { @@ -63,4 +69,4 @@ Thumbnail.prototype.queue = function () { } Thumbnail.processQueue(); return this.loadingDeferred; -}; +}; \ No newline at end of file diff --git a/templates/index.php b/templates/index.php index 0201ac6..49c0b39 100644 --- a/templates/index.php +++ b/templates/index.php @@ -8,3 +8,4 @@
+
\ No newline at end of file From 07258ba3f6ff03770f5a0baec459163159b4433c Mon Sep 17 00:00:00 2001 From: jbtbnl Date: Tue, 25 Mar 2014 18:35:11 +0100 Subject: [PATCH 3/5] Navigation through albums now working in seamless gallery. --- css/styles.css | 40 +++----------------- js/gallery.js | 86 +++++-------------------------------------- js/seamlessgallery.js | 41 +++++++++++++++++++-- js/seamlessimage.js | 5 ++- js/slideshow.js | 2 +- js/thumbnail.js | 2 +- 6 files changed, 59 insertions(+), 117 deletions(-) diff --git a/css/styles.css b/css/styles.css index fba457c..9b32f00 100644 --- a/css/styles.css +++ b/css/styles.css @@ -67,25 +67,15 @@ button.share { transform: rotate(-1.5deg); } -#gallery > a.album > img { - width: 200px; - height: 200px; - border-radius: 5px; - border: 1px solid #ccc; -} - -#gallery > a.album > label { - color: white; - text-shadow: 0 0 10px #000; - position: absolute; - bottom: 0; - width: 100%; +#gallery a.album label, #gallery a.image label { + color: rgb(255, 255, 255); + text-shadow: 0 0 7px rgb(0, 0, 0); + position: relative; + bottom: 15px; + left: 10px; text-align: center; font-size: 18px; - padding-bottom: 5px; - overflow: hidden; text-overflow: ellipsis; - z-index: 11; } #gallery > a { @@ -96,24 +86,6 @@ button.share { zoom: 1; } -#gallery > a.image >img { - max-height: 200px; -} - -#gallery > a.album, -#gallery > a.image{ - opacity: 1; - transition: opacity 500ms; - -moz-transition: opacity 500ms; - -o-transition: opacity 500ms; - -ms-transition: opacity 500ms; - -webkit-transition: opacity 500ms; -} -#gallery > a.album.loading, -#gallery > a.image.loading{ - opacity: 0; -} - #controls > .right { float: right; } diff --git a/js/gallery.js b/js/gallery.js index dbb3eda..ce5afd9 100644 --- a/js/gallery.js +++ b/js/gallery.js @@ -5,7 +5,7 @@ Gallery.currentAlbum = ''; Gallery.subAlbums = {}; Gallery.users = []; Gallery.displayNames = []; -Gallery.seamlessGallery = new SeamlessGallery('#gallery', 150); +Gallery.seamlessGallery = new SeamlessGallery('#gallery', 175); Gallery.resizeTriggered = false; $(window).resize(function() { @@ -163,7 +163,7 @@ Gallery.view.addImage = function (image) { thumb = Thumbnail.get(image); thumb.queue().then(function (thumb) { if($.inArray(image, Gallery.albums[Gallery.currentAlbum]) === -1) return; // filter out images removed from queue but already loading - var seamlessImage = new SeamlessImage(thumb, image, Gallery.getImage(image), ''); + var seamlessImage = new SeamlessImage(thumb, image, Gallery.getImage(image), null); Gallery.seamlessGallery.add(seamlessImage); Gallery.view.cache[image] = seamlessImage; }); @@ -175,80 +175,16 @@ Gallery.view.addAlbum = function (path, name) { var link, image, label, thumbs, thumb; name = name || OC.basename(path); if (Gallery.view.cache[path]) { - thumbs = Gallery.view.addAlbum.thumbs[path]; - Gallery.view.element.append(Gallery.view.cache[path]); - //event handlers are removed when using clear() - Gallery.view.cache[path].mousemove(function (event) { - Gallery.view.addAlbum.mouseEvent.call(Gallery.view.cache[path], thumbs, event); - }); - thumb = Thumbnail.get(thumbs[0], true); - thumb.queue(); + Gallery.seamlessGallery.addAlbum(Gallery.view.cache[path]); } else { thumbs = Gallery.getAlbumThumbnailPaths(path); - Gallery.view.addAlbum.thumbs[path] = thumbs; - link = $('
'); - label = $('
'); row.addClass('row'); @@ -70,7 +89,21 @@ SeamlessGallery.prototype.redraw = function() { this.draw(); }; +SeamlessGallery.prototype.run = function() { + this.paused = false; + this.draw(); +}; + +SeamlessGallery.prototype.pause = function() { + this.paused = true; +}; + SeamlessGallery.prototype.clear = function() { this.images = new Array(); this.currentElement = 0; + this.length = 0; + this.albumLength = 0; + this.albumLoaded = 0; + this.paused = true; + $('#loading').show(); }; \ No newline at end of file diff --git a/js/seamlessimage.js b/js/seamlessimage.js index c956623..4541a08 100644 --- a/js/seamlessimage.js +++ b/js/seamlessimage.js @@ -14,7 +14,7 @@ function SeamlessImage(image, dataPath, href, name) { SeamlessImage.prototype.render = function(scale) { var link = $(''); - link.addClass('image'); + (this.name === null) ? link.addClass('image') : link.addClass('album'); link.attr('data-path', this.dataPath); link.attr('href', this.href); link.css('height', (Math.floor(this.height() * scale * 10) / 10) - this.padding*2); @@ -23,6 +23,9 @@ SeamlessImage.prototype.render = function(scale) { image.css('height', (Math.floor(this.height() * scale * 10) / 10) - this.padding*2); image.css('width', (Math.floor(this.width() * scale * 10) / 10) - this.padding*2); link.append(image); + var label = $('