Add slideshow for images
This commit is contained in:
@@ -3,6 +3,8 @@ Version 1.0.36 (unreleased)
|
|||||||
|
|
||||||
New features:
|
New features:
|
||||||
|
|
||||||
|
* Add slideshow for images
|
||||||
|
|
||||||
Improvements:
|
Improvements:
|
||||||
|
|
||||||
* Replace Chosen jQuery plugin by custom UI component
|
* Replace Chosen jQuery plugin by custom UI component
|
||||||
|
|||||||
@@ -2,7 +2,16 @@
|
|||||||
<div class="file-thumbnails">
|
<div class="file-thumbnails">
|
||||||
<?php foreach ($images as $file): ?>
|
<?php foreach ($images as $file): ?>
|
||||||
<div class="file-thumbnail">
|
<div class="file-thumbnail">
|
||||||
<a href="<?= $this->url->href('FileViewerController', 'show', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>" class="popover"><img src="<?= $this->url->href('FileViewerController', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $project['id'])) ?>" title="<?= $this->text->e($file['name']) ?>" alt="<?= $this->text->e($file['name']) ?>"></a>
|
<?= $this->app->component('image-slideshow', array(
|
||||||
|
'images' => $images,
|
||||||
|
'image' => $file,
|
||||||
|
'regex' => 'FILE_ID',
|
||||||
|
'url' => array(
|
||||||
|
'image' => $this->url->to('FileViewerController', 'image', array('file_id' => 'FILE_ID', 'project_id' => $project['id'])),
|
||||||
|
'thumbnail' => $this->url->to('FileViewerController', 'thumbnail', array('file_id' => 'FILE_ID', 'project_id' => $project['id'])),
|
||||||
|
)
|
||||||
|
)) ?>
|
||||||
|
|
||||||
<div class="file-thumbnail-content">
|
<div class="file-thumbnail-content">
|
||||||
<div class="file-thumbnail-title">
|
<div class="file-thumbnail-title">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
|
|||||||
@@ -2,7 +2,16 @@
|
|||||||
<div class="file-thumbnails">
|
<div class="file-thumbnails">
|
||||||
<?php foreach ($images as $file): ?>
|
<?php foreach ($images as $file): ?>
|
||||||
<div class="file-thumbnail">
|
<div class="file-thumbnail">
|
||||||
<a href="<?= $this->url->href('FileViewerController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>" class="popover"><img src="<?= $this->url->href('FileViewerController', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" title="<?= $this->text->e($file['name']) ?>" alt="<?= $this->text->e($file['name']) ?>"></a>
|
<?= $this->app->component('image-slideshow', array(
|
||||||
|
'images' => $images,
|
||||||
|
'image' => $file,
|
||||||
|
'regex' => 'FILE_ID',
|
||||||
|
'url' => array(
|
||||||
|
'image' => $this->url->to('FileViewerController', 'image', array('file_id' => 'FILE_ID', 'project_id' => $task['project_id'], 'task_id' => $task['id'])),
|
||||||
|
'thumbnail' => $this->url->to('FileViewerController', 'thumbnail', array('file_id' => 'FILE_ID', 'project_id' => $task['project_id'], 'task_id' => $task['id'])),
|
||||||
|
)
|
||||||
|
)) ?>
|
||||||
|
|
||||||
<div class="file-thumbnail-content">
|
<div class="file-thumbnail-content">
|
||||||
<div class="file-thumbnail-title">
|
<div class="file-thumbnail-title">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
|
|||||||
2
assets/css/app.min.css
vendored
2
assets/css/app.min.css
vendored
File diff suppressed because one or more lines are too long
4
assets/js/app.min.js
vendored
4
assets/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
153
assets/js/components/image-slideshow.js
Normal file
153
assets/js/components/image-slideshow.js
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
KB.component('image-slideshow', function (containerElement, options) {
|
||||||
|
var currentImage;
|
||||||
|
|
||||||
|
function onKeyDown(e) {
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 27:
|
||||||
|
destroySlide();
|
||||||
|
break;
|
||||||
|
case 39:
|
||||||
|
renderNextSlide();
|
||||||
|
break;
|
||||||
|
case 37:
|
||||||
|
renderPreviousSlide();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onOverlayClick(element) {
|
||||||
|
if (element.matches('.slideshow-next-icon')) {
|
||||||
|
renderNextSlide();
|
||||||
|
} else if (element.matches('.slideshow-previous-icon')) {
|
||||||
|
renderPreviousSlide();
|
||||||
|
} else {
|
||||||
|
destroySlide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClick(element) {
|
||||||
|
var imageId = KB.dom(element).data('imageId');
|
||||||
|
var image = getImage(imageId);
|
||||||
|
|
||||||
|
renderSlide(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNextSlide() {
|
||||||
|
destroySlide();
|
||||||
|
|
||||||
|
for (var i = 0; i < options.images.length; i++) {
|
||||||
|
if (options.images[i].id === currentImage.id) {
|
||||||
|
var index = i + 1;
|
||||||
|
|
||||||
|
if (index >= options.images.length) {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentImage = options.images[index];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSlide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPreviousSlide() {
|
||||||
|
destroySlide();
|
||||||
|
|
||||||
|
for (var i = 0; i < options.images.length; i++) {
|
||||||
|
if (options.images[i].id === currentImage.id) {
|
||||||
|
var index = i - 1;
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
index = options.images.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentImage = options.images[index];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSlide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSlide() {
|
||||||
|
var closeElement = KB.dom('div')
|
||||||
|
.attr('class', 'fa fa-window-close slideshow-icon slideshow-close-icon')
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var previousElement = KB.dom('div')
|
||||||
|
.attr('class', 'fa fa-chevron-circle-left slideshow-icon slideshow-previous-icon')
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var nextElement = KB.dom('div')
|
||||||
|
.attr('class', 'fa fa-chevron-circle-right slideshow-icon slideshow-next-icon')
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var imageElement = KB.dom('img')
|
||||||
|
.attr('src', getUrl(currentImage, 'image'))
|
||||||
|
.attr('alt', currentImage.name)
|
||||||
|
.attr('title', currentImage.name)
|
||||||
|
.style('maxHeight', (window.innerHeight - 50) + 'px')
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var captionElement = KB.dom('figcaption')
|
||||||
|
.text(currentImage.name)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var figureElement = KB.dom('figure')
|
||||||
|
.add(imageElement)
|
||||||
|
.add(captionElement)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var overlayElement = KB.dom('div')
|
||||||
|
.addClass('image-slideshow-overlay')
|
||||||
|
.add(closeElement)
|
||||||
|
.add(previousElement)
|
||||||
|
.add(nextElement)
|
||||||
|
.add(figureElement)
|
||||||
|
.click(onOverlayClick)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
document.body.appendChild(overlayElement);
|
||||||
|
document.addEventListener('keydown', onKeyDown, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroySlide() {
|
||||||
|
var overlayElement = KB.find('.image-slideshow-overlay');
|
||||||
|
|
||||||
|
if (overlayElement !== null) {
|
||||||
|
document.removeEventListener('keydown', onKeyDown, false);
|
||||||
|
overlayElement.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImage(imageId) {
|
||||||
|
for (var i = 0; i < options.images.length; i++) {
|
||||||
|
if (options.images[i].id === imageId) {
|
||||||
|
return options.images[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUrl(image, type) {
|
||||||
|
var regex = new RegExp(options.regex, 'g');
|
||||||
|
return options.url[type].replace(regex, image.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildThumbnailElement(image) {
|
||||||
|
return KB.dom('img')
|
||||||
|
.attr('src', getUrl(image, 'thumbnail'))
|
||||||
|
.attr('alt', image.name)
|
||||||
|
.attr('title', image.name)
|
||||||
|
.data('imageId', image.id)
|
||||||
|
.click(onClick)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.render = function () {
|
||||||
|
currentImage = options.image;
|
||||||
|
containerElement.appendChild(buildThumbnailElement(currentImage));
|
||||||
|
};
|
||||||
|
});
|
||||||
40
assets/sass/_image_slideshow.sass
Normal file
40
assets/sass/_image_slideshow.sass
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
.image-slideshow-overlay
|
||||||
|
position: fixed
|
||||||
|
top: 0
|
||||||
|
left: 0
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
background: rgba(0, 0, 0, 0.95)
|
||||||
|
overflow: auto
|
||||||
|
z-index: 100
|
||||||
|
img
|
||||||
|
display: block
|
||||||
|
margin: auto
|
||||||
|
figcaption
|
||||||
|
color: #fff
|
||||||
|
opacity: 0.7
|
||||||
|
position: absolute
|
||||||
|
bottom: 5px
|
||||||
|
right: 15px
|
||||||
|
|
||||||
|
.slideshow-icon
|
||||||
|
color: #fff
|
||||||
|
position: absolute
|
||||||
|
font-size: 2.5em
|
||||||
|
opacity: 0.6
|
||||||
|
&:hover
|
||||||
|
opacity: 0.9
|
||||||
|
cursor: pointer
|
||||||
|
|
||||||
|
.slideshow-previous-icon
|
||||||
|
left: 10px
|
||||||
|
top: 45%
|
||||||
|
|
||||||
|
.slideshow-next-icon
|
||||||
|
right: 10px
|
||||||
|
top: 45%
|
||||||
|
|
||||||
|
.slideshow-close-icon
|
||||||
|
right: 10px
|
||||||
|
top: 10px
|
||||||
|
font-size: 1.4em
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
box-shadow: 4px 2px 10px -6px rgba(0, 0, 0, 0.55)
|
box-shadow: 4px 2px 10px -6px rgba(0, 0, 0, 0.55)
|
||||||
margin-right: 15px
|
margin-right: 15px
|
||||||
img
|
img
|
||||||
|
cursor: pointer
|
||||||
border-top-left-radius: 5px
|
border-top-left-radius: 5px
|
||||||
border-top-right-radius: 5px
|
border-top-right-radius: 5px
|
||||||
&:hover
|
&:hover
|
||||||
|
|||||||
@@ -52,3 +52,4 @@
|
|||||||
@import activity_stream
|
@import activity_stream
|
||||||
@import gantt_chart
|
@import gantt_chart
|
||||||
@import user_mentions
|
@import user_mentions
|
||||||
|
@import image_slideshow
|
||||||
|
|||||||
Reference in New Issue
Block a user