Mobile and swipe support

This commit is contained in:
Kujiu 2021-07-25 01:54:37 +02:00
parent 69b2f6fa04
commit 5bd4bd72d6
Signed by: kujiu
GPG key ID: ABBB2CAC6855599F
19 changed files with 344 additions and 117 deletions

1
.gitignore vendored
View file

@ -275,3 +275,4 @@ dmypy.json
# Cython debug symbols # Cython debug symbols
cython_debug/ cython_debug/
errorlog

View file

@ -1,27 +1,34 @@
=======
Changes Changes
======= #######
1.1.0 (*2021-07-24*)
~~~~~~~~~~~~~~~~~~~~
- Better compatibility with mobile phones and small screens
- Swipe support
- More space for images
- Restructure repository
1.0.3 (*2021-07-13*) 1.0.3 (*2021-07-13*)
==================== ~~~~~~~~~~~~~~~~~~~~
- Fix height on prev/next buttons - Fix height on prev/next buttons
1.0.2 (*2021-07-13*) 1.0.2 (*2021-07-13*)
==================== ~~~~~~~~~~~~~~~~~~~~
- Fix scroll computation - Fix scroll computation
- Translation of ignored elements - Translation of ignored elements
- Improve accessibility - Improve accessibility
1.0.1 (*2021-06-03*) 1.0.1 (*2021-06-03*)
==================== ~~~~~~~~~~~~~~~~~~~~
- Fix translation - Fix translation
- Add timer option - Add timer option
- Better CSS and transition - Better CSS and transition
1.0.0 (*2021-05-28*) 1.0.0 (*2021-05-28*)
==================== ~~~~~~~~~~~~~~~~~~~~
- Initial release - Initial release

2
MANIFEST.in Normal file
View file

@ -0,0 +1,2 @@
include VERSION
include CHANGES

21
Makefile Normal file
View file

@ -0,0 +1,21 @@
PYTHON = python3
SRCDIR = .
DISTDIR = ./dist
BUILDDIR = ./build
all: sdist wheel
clean:
rm -rf *.egg-info dist build
sdist:
$(PYTHON) -m build $(SRCDIR) -o $(DISTDIR) -sn
wheel:
$(PYTHON) -m build $(SRCDIR) -o $(BUILDDIR) -wn
install:
pip uninstall -y sphinx-galleria
pip install $(DISTDIR)/sphinx_galleria-`cat $(SRCDIR)/VERSION`.tar.gz
.PHONY: clean sdist wheel install

1
VERSION Normal file
View file

@ -0,0 +1 @@
1.1.0

View file

@ -14,8 +14,12 @@ from PIL import Image
from . import directive from . import directive
from . import collector from . import collector
__version_info__ = (1, 0, 3)
__version__ = '.'.join([str(val) for val in __version_info__]) with open(os.path.join(
os.path.dirname(__file__),
'VERSION')) as version_file:
__version__ = version_file.read().strip()
__version_info__ = tuple(int(v) for v in __version__.split('.'))
def copy_images_files(app: Sphinx, env: BuildEnvironment) -> None: def copy_images_files(app: Sphinx, env: BuildEnvironment) -> None:

6
pyproject.toml Normal file
View file

@ -0,0 +1,6 @@
[build-system]
requires = [
"setuptools>=56",
"wheel"
]
build-backend = "setuptools.build_meta"

View file

@ -1,2 +1,4 @@
Sphinx Sphinx
Pillow Pillow
setuptools>=56
build

View file

@ -1,11 +1,61 @@
[metadata] [metadata]
description-file = README.rst long_description = file: README.rst, CHANGES.rst
license-files = long_description_content_type = text/x-rst
license_files =
LICENSE LICENSE
LICENSE-de LICENSE-de
LICENSE-fr LICENSE-fr
LICENSE-nl LICENSE-nl
name = sphinx_galleria
version = file: VERSION
url = https://procrastinator.nerv-project.eu/nerv-project/sphinx_galleria
license = EUPL 1.2
author = Kujiu
author_email = kujiu-pypi@kujiu.org
description = Create image galleries with Sphinx
platform = any
classifiers =
Framework :: Sphinx
Framework :: Sphinx :: Extension
Development Status :: 5 - Production/Stable
Environment :: Console
Environment :: Web Environment
Intended Audience :: Developers
License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Operating System :: OS Independent
Topic :: Documentation
Topic :: Software Development :: Documentation
keywords = sphinx image gallery
project_urls =
Source Code = https://procrastinator.nerv-project.eu/nerv-project/sphinx_galleria
Bug Tracker = https://procrastinator.nerv-project.eu/nerv-project/sphinx_galleria/issues
[options]
install_requires =
Sphinx>=3.0.0
Pillow
packages = sphinx_galleria
package_dir =
sphinx_galleria = .
# cmdclass =
# compile_catalog = babel.messages.frontend.compile_catalog,
# extract_messages = babel.messages.frontend.extract_messages,
# init_catalog = babel.messages.frontend.init_catalog,
# update_catalog = babel.messages.frontend.update_catalog
[options.package_data]
sphinx_galleria =
VERSION
static/sphinxgalleria/*.mjs
static/sphinxgalleria/*.css
locale/*.pot
locale/*/LC_MESSAGES/*.po
locale/*/LC_MESSAGES/*.mo
[extract_messages] [extract_messages]
mapping_file = babel.cfg mapping_file = babel.cfg

View file

@ -1,58 +0,0 @@
from setuptools import setup
from babel.messages import frontend as babel
with open("README.rst", "r") as fh:
long_description = fh.read()
setup(
name="sphinx_galleria",
version="1.0.3",
url="https://procrastinator.nerv-project.eu/nerv-project/sphinx_galleria",
license="EUPL 1.2",
author="Kujiu",
author_email="kujiu-pypi@kujiu.org",
description="Create image galleries with Sphinx",
long_description=long_description,
long_description_content_type="text/x-rst",
packages=["sphinx_galleria"],
cmdclass={
'compile_catalog': babel.compile_catalog,
'extract_messages': babel.extract_messages,
'init_catalog': babel.init_catalog,
'update_catalog': babel.update_catalog
},
package_data={
"sphinx_galleria": [
"*.py",
"static/sphinxgalleria/*.mjs",
"static/sphinxgalleria/*.css",
"locale/*.pot",
"locale/*/LC_MESSAGES/*.po",
"locale/*/LC_MESSAGES/*.mo",
]
},
install_requires=["sphinx>=3.0.0"],
classifiers=[
"Framework :: Sphinx",
"Framework :: Sphinx :: Extension",
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Operating System :: OS Independent",
"Topic :: Documentation",
"Topic :: Software Development :: Documentation",
],
keywords="sphinx image gallery",
project_urls={
"Source": "https://procrastinator.nerv-project.eu/nerv-project/sphinx_galleria",
"Issues": "https://procrastinator.nerv-project.eu/nerv-project/sphinx_galleria/issues",
},
)

View file

@ -31,8 +31,7 @@
} }
.sphinxgalleria-core figure .row { .sphinxgalleria-core figure .row {
flex-flow: row nowrap; position: relative;
display: flex;
flex-shrink: 1000; flex-shrink: 1000;
flex-grow: 1000; flex-grow: 1000;
} }
@ -53,8 +52,7 @@
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; position: relative;
flex-flow: column nowrap;
background-color: transparent; background-color: transparent;
} }
@ -173,14 +171,13 @@
.sphinxgalleria-core dialog { .sphinxgalleria-core dialog {
position: absolute; position: absolute;
top: 3vh; top: 2.5vh;
left: 0; left: 0;
height: 90vh; max-height: 95vh;
max-height: 90vh;
width: max-content; width: max-content;
margin: 0 auto 0 auto; margin: auto;
padding-left: 3rem; padding-left: 2vw;
padding-right: 3rem; padding-right: 2vw;
background-color: black; background-color: black;
color: white; color: white;
border: white solid 0.2rem; border: white solid 0.2rem;
@ -192,7 +189,9 @@
.sphinxgalleria-core dialog img { .sphinxgalleria-core dialog img {
height: 100%; height: 100%;
width: auto; width: 100%;
max-width: 90vw !important;
max-height: 90vh !important;
object-fit: contain; object-fit: contain;
flex-grow: 1000; flex-grow: 1000;
flex-shrink: 1000; flex-shrink: 1000;
@ -227,16 +226,17 @@
.sphinxgalleria-core dialog header button { .sphinxgalleria-core dialog header button {
position: absolute; position: absolute;
top: .5rem; top: .5rem;
right: -.5rem; right: 0;
background: transparent;
} }
.sphinxgalleria-core dialog header button::after { .sphinxgalleria-core dialog header button::after {
content: '✕'; content: '✕';
text-shadow: .1rem .05rem black;
} }
.sphinxgalleria-core dialog header { .sphinxgalleria-core dialog header {
position: relative; position: relative;
min-height: 3rem;
} }
.sphinxgalleria-core dialog menu { .sphinxgalleria-core dialog menu {
@ -257,6 +257,10 @@
.sphinxgalleria-core figure button.prev, .sphinxgalleria-core figure button.prev,
.sphinxgalleria-core figure button.next { .sphinxgalleria-core figure button.next {
position: absolute;
top: 0;
bottom: 0;
z-index: 100;
color: hsl(0, 0%, 34%); color: hsl(0, 0%, 34%);
background-color: transparent; background-color: transparent;
font-size: 4rem; font-size: 4rem;
@ -276,11 +280,23 @@
transition: color ease .4s; transition: color ease .4s;
} }
.sphinxgalleria-core figure button.prev {
left: 0;
}
.sphinxgalleria-core figure button.next {
right: 0;
}
.sphinxgalleria-core figure button.prev::before, .sphinxgalleria-core figure button.prev::before,
.sphinxgalleria-core dialog menu button.prev::before { .sphinxgalleria-core dialog menu button.prev::before {
content: '<'; content: '<';
} }
.sphinxgalleria-core dialog menu button.next {
float: right;
}
.sphinxgalleria-core figure button.next::after, .sphinxgalleria-core figure button.next::after,
.sphinxgalleria-core dialog menu button.next::after { .sphinxgalleria-core dialog menu button.next::after {
margin-left: 0.5rem; margin-left: 0.5rem;

View file

@ -7,6 +7,17 @@ export class SphinxGalleria {
self.options = options; self.options = options;
self.data = data; self.data = data;
self.oneimage = self.data.length === 1; self.oneimage = self.data.length === 1;
self.swipe_delay = 1500;
self.touch_data = {
id: -1,
x: null,
y: null,
current_x: null,
current_y: null,
interval: null,
swiped: false,
noclick: false
};
self.node_target = null; self.node_target = null;
self.node_figure = document.createElement('figure'); self.node_figure = document.createElement('figure');
@ -35,9 +46,6 @@ export class SphinxGalleria {
var figure_row = document.createElement('div'); var figure_row = document.createElement('div');
figure_row.classList.add('row'); figure_row.classList.add('row');
self.dialog_button_close = document.createElement('button');
self.dialog_button_close.classList.add('close');
self.dialog_button_close_icon = document.createElement('button'); self.dialog_button_close_icon = document.createElement('button');
self.dialog_button_close_icon.setAttribute('aria-label', self.options.label_close); self.dialog_button_close_icon.setAttribute('aria-label', self.options.label_close);
@ -90,13 +98,10 @@ export class SphinxGalleria {
self.button_modal.appendChild(self.node_image); self.button_modal.appendChild(self.node_image);
self.button_modal.appendChild(self.node_div_caption); self.button_modal.appendChild(self.node_div_caption);
self.dialog_button_close.appendChild(document.createTextNode(self.options.label_close));
dialog_header.appendChild(self.dialog_title); dialog_header.appendChild(self.dialog_title);
dialog_header.appendChild(self.dialog_button_close_icon); dialog_header.appendChild(self.dialog_button_close_icon);
self.node_dialog.appendChild(dialog_header); self.node_dialog.appendChild(dialog_header);
self.node_dialog.appendChild(self.dialog_image); self.node_dialog.appendChild(self.dialog_image);
dialog_menu.appendChild(self.dialog_button_close);
self.node_dialog.appendChild(dialog_menu); self.node_dialog.appendChild(dialog_menu);
if(!self.oneimage) { if(!self.oneimage) {
@ -119,30 +124,38 @@ export class SphinxGalleria {
self.node_target.appendChild(self.node_thumbnails); self.node_target.appendChild(self.node_thumbnails);
self.node_target.appendChild(self.node_mask); self.node_target.appendChild(self.node_mask);
var onmodal = function(event) { var onmodal = function(ev) {
var key = event.key; if(self.touch_data.noclick) {
if(event.type==='keypress' && key!==" " && key!=="Enter") { self.touch_data.noclick = false;
ev.preventDefault();
return; return;
} }
event.preventDefault(); var key = ev.key;
if(ev.type==='keypress' && key!==" " && key!=="Enter") {
return;
}
ev.preventDefault();
self.showModal(); self.showModal();
}; };
self.button_modal.addEventListener('click', onmodal); self.button_modal.addEventListener('click', onmodal);
self.button_modal.addEventListener('keypress', onmodal); self.button_modal.addEventListener('keypress', onmodal);
var onclose = function(event) { var onclose = function(ev) {
var key = event.key; if(self.touch_data.noclick) {
if(event.type==='keypress' && key!==" " && key!=="Enter") { self.touch_data.noclick = false;
ev.preventDefault();
return; return;
} }
event.preventDefault(); var key = ev.key;
if(ev.type==='keypress' && key!==" " && key!=="Enter") {
return;
}
ev.preventDefault();
self.closeModal(); self.closeModal();
}; };
self.node_mask.addEventListener('click', onclose); self.node_mask.addEventListener('click', onclose);
self.node_dialog.addEventListener('click', function(e) {e.stopPropagation();}); self.node_dialog.addEventListener('click', function(ev) {ev.stopPropagation();});
self.dialog_button_close.addEventListener('click', onclose);
self.dialog_button_close.addEventListener('keypress', onclose);
self.dialog_button_close_icon.addEventListener('click', onclose); self.dialog_button_close_icon.addEventListener('click', onclose);
self.dialog_button_close_icon.addEventListener('keypress', onclose); self.dialog_button_close_icon.addEventListener('keypress', onclose);
@ -153,21 +166,67 @@ export class SphinxGalleria {
}, self.options.timer*1000); }, self.options.timer*1000);
} }
var onprev = function(event) { var startSwipe = function(ev) {self.startSwipe(ev);};
var key = event.key; var moveSwipe = function(ev) {self.moveSwipe(ev);};
if(event.type==='keypress' && key!==" " && key!=="Enter") { var endSwipe = function(ev) {self.endSwipe(ev);};
self.node_mask.addEventListener('touchstart', startSwipe, true);
self.node_mask.addEventListener('touchmove', moveSwipe, true);
self.node_mask.addEventListener('touchend', endSwipe, true);
self.node_target.addEventListener('touchstart', startSwipe, true);
self.node_target.addEventListener('touchmove', moveSwipe);
self.node_target.addEventListener('touchend', endSwipe, true);
self.node_image.addEventListener('touchstart', startSwipe, true);
self.node_image.addEventListener('touchmove', moveSwipe);
self.node_image.addEventListener('touchend', endSwipe, true);
self.dialog_image.addEventListener('touchstart', startSwipe, true);
self.dialog_image.addEventListener('touchmove', moveSwipe);
self.dialog_image.addEventListener('touchend', endSwipe, true);
self.node_mask.addEventListener('mousedown', startSwipe, true);
self.node_mask.addEventListener('mousemove', moveSwipe, true);
self.node_mask.addEventListener('mouseup', endSwipe, true);
self.node_target.addEventListener('mousedown', startSwipe, true);
self.node_target.addEventListener('mousemove', moveSwipe, true);
self.node_target.addEventListener('mouseup', endSwipe, true);
self.node_image.addEventListener('mousedown', startSwipe, true);
self.node_image.addEventListener('mousemove', moveSwipe, true);
self.node_image.addEventListener('mouseup', endSwipe, true);
self.dialog_image.addEventListener('mousedown', startSwipe, true);
self.dialog_image.addEventListener('mousemove', moveSwipe, true);
self.dialog_image.addEventListener('mouseup', endSwipe, true);
var removeClick = function(ev) {
if(self.touch_data.noclick) {
self.touch_data.noclick = false;
ev.preventDefault();
ev.stopImmediatePropagation();
}
};
self.node_mask.addEventListener('click', removeClick, true);
self.node_target.addEventListener('click', removeClick, true);
var onprev = function(ev) {
var key = ev.key;
if(ev.type==='keypress' && key!==" " && key!=="Enter") {
return; return;
} }
event.preventDefault(); ev.preventDefault();
self.prev(); self.prev();
}; };
var onnext = function(event) { var onnext = function(ev) {
var key = event.key; var key = ev.key;
if(event.type==='keypress' && key!==" " && key!=="Enter") { if(ev.type==='keypress' && key!==" " && key!=="Enter") {
return; return;
} }
event.preventDefault(); ev.preventDefault();
self.next(); self.next();
}; };
@ -183,14 +242,19 @@ export class SphinxGalleria {
self.dialog_button_next.addEventListener('keypress', onnext); self.dialog_button_next.addEventListener('keypress', onnext);
self.dialog_button_next.addEventListener('click', onnext); self.dialog_button_next.addEventListener('click', onnext);
self.dialog_image.addEventListener('click', function(e) { self.dialog_image.addEventListener('click', function(ev) {
var x = e.layerX - e.target.x; if(self.touch_data.noclick) {
if(x < e.target.width/2) { self.touch_data.noclick = false;
ev.preventDefault();
return;
}
var x = ev.layerX - ev.target.x;
if(x < ev.target.width/2) {
self.prev(); self.prev();
e.preventDefault(); ev.preventDefault();
} else if(x > e.target.width/2) { } else if(x > ev.target.width/2) {
self.next(); self.next();
e.preventDefault(); ev.preventDefault();
} }
}); });
@ -246,8 +310,8 @@ export class SphinxGalleria {
image_button.addEventListener('change', function() {self.changeImage();}); image_button.addEventListener('change', function() {self.changeImage();});
}); });
document.addEventListener('keydown', function(event) { document.addEventListener('keydown', function(ev) {
var key = event.key; var key = ev.key;
if(!self.node_dialog.open && !self.node_target.contains(document.activeElement)) { if(!self.node_dialog.open && !self.node_target.contains(document.activeElement)) {
return; return;
@ -255,13 +319,13 @@ export class SphinxGalleria {
if(!self.oneimage && key==="ArrowLeft") { if(!self.oneimage && key==="ArrowLeft") {
self.prev(); self.prev();
event.preventDefault(); ev.preventDefault();
} else if(!self.oneimage && key==="ArrowRight") { } else if(!self.oneimage && key==="ArrowRight") {
self.next(); self.next();
event.preventDefault(); ev.preventDefault();
} else if(key==="Escape") { } else if(key==="Escape") {
self.closeModal(); self.closeModal();
event.preventDefault(); ev.preventDefault();
} }
}); });
@ -408,4 +472,115 @@ export class SphinxGalleria {
this.node_mask.hidden = true; this.node_mask.hidden = true;
this.node_mask.setAttribute('aria-hidden', true); this.node_mask.setAttribute('aria-hidden', true);
} }
startSwipe(ev) {
var self = this;
if(!self.oneimage && self.touch_data.id === -1) {
ev.preventDefault();
if(ev.type === 'touchstart') {
self.touch_data.id = ev.changedTouches[0].identifier;
self.touch_data.x = ev.changedTouches[0].clientX;
self.touch_data.y = ev.changedTouches[1].clientY;
} else {
self.touch_data.id = -2;
self.touch_data.x = ev.clientX;
self.touch_data.y = ev.clientY;
}
self.touch_data.current_x = self.touch_data.x;
self.touch_data.current_y = self.touch_data.y;
if(!self.touch_data.interval) {
self.touch_data.interval = setInterval(function() {
self.swipeItem();
}, self.swipe_delay);
}
}
}
moveSwipe(ev) {
var self = this;
var move = false;
if(!self.oneimage && self.touch_data.x) {
ev.preventDefault();
if(ev.type === 'touchmove') {
ev.changedTouches.forEach(function(touch) {
if(touch.identifier === self.touch_data.id) {
move = true;
self.touch_data.current_x = touch.clientX;
}
});
} else if(ev.which > 0) {
move = true;
self.touch_data.current_x = ev.clientX;
}
}
}
endSwipe(ev) {
var self = this;
var stop = false;
if(!self.oneimage && self.touch_data.x) {
ev.preventDefault();
if(ev.type === "touchend") {
ev.changedTouches.forEach(function(touch) {
if(touch.identifier === self.touch_data.id) {
stop = true;
self.touch_data.current_x = touch.clientX;
self.touch_data.current_y = touch.clientY;
}
});
} else {
stop = true;
self.touch_data.current_x = ev.clientX;
self.touch_data.current_y = ev.clientY;
}
if(stop) {
self.touch_data.id = -1;
if(self.touch_data.interval) {
clearInterval(self.touch_data.interval);
self.touch_data.interval = null;
}
if(!self.touch_data.swiped) {
self.swipeItem();
}
self.touch_data.x = null;
self.touch_data.y = null;
self.touch_data.current_x = null;
self.touch_data.current_y = null;
self.touch_data.swiped = false;
}
}
}
swipeItem() {
var self = this;
var width = self.touch_data.current_x - self.touch_data.x;
var height = self.touch_data.current_y - self.touch_data.y;
if(Math.abs(width) > self.getMinWidthSwipe()) {
if(width > 0) {
self.next(true);
self.touch_data.noclick = true;
self.touch_data.swiped = true;
} else {
self.prev(true);
self.touch_data.noclick = true;
self.touch_data.swiped = true;
}
} else if(Math.abs(height) > self.node_mask.clientHeight/2) {
self.closeModal();
self.touch_data.noclick = true;
}
}
getMinWidthSwipe() {
if(this.node_mask.hidden) {
return this.node_image.clientWidth/2;
}
return this.dialog_image.clientWidth/2;
}
} }