Code working but some features missing and glitches
This commit is contained in:
parent
adaa36dcf0
commit
ebfbd3b6fc
8 changed files with 772 additions and 101 deletions
40
README.rst
40
README.rst
|
@ -1,7 +1,8 @@
|
|||
sphinx_galleria
|
||||
###############
|
||||
|
||||
Create image galleries with Sphinx.
|
||||
Create image galleries with Sphinx. No external JS
|
||||
dependency.
|
||||
|
||||
Install
|
||||
~~~~~~~
|
||||
|
@ -12,6 +13,11 @@ If you're using a virtualenv, just:
|
|||
|
||||
pip install sphinx-galleria
|
||||
|
||||
.. important::
|
||||
|
||||
Your webserver must deliver .mjs file with correct
|
||||
content type (`application/javascript`).
|
||||
|
||||
Using
|
||||
~~~~~
|
||||
|
||||
|
@ -23,24 +29,30 @@ Just use the galleria directive like this:
|
|||
.. code:: rst
|
||||
|
||||
.. galleria:: imagefile1 imagefile2 images*.jpg
|
||||
:galleria: (optional) Name of gallery
|
||||
:description: (optional) A long description
|
||||
:title: (optional) Title of image
|
||||
:thumbsize: (optional) Image size (defaults to "100x100")
|
||||
:transition: (optional, once) Transition for gallery
|
||||
:theme: (optional, once) Theme name for galleria
|
||||
:class: (optional, once) HTML class for gallery
|
||||
:galleria: (optional) Name of gallery - node level
|
||||
:alt: (optional) A long description - image level
|
||||
:title: (optional) Title of image - image level
|
||||
:thumbsize: (optional) Image size (defaults to "100x100") - image level
|
||||
:width: Width of image (in pixel or percentage or with unit, default auto) - node level
|
||||
:height: (optional) Height of image (in pixel or with unit) - node level
|
||||
:align: Align to 'right', 'left' or 'center' (default to center) - node level
|
||||
:hide_title: Flag - hide title under image (not in dialog) - image level
|
||||
:hide_alt: Flag - hide alternative text under image - image level
|
||||
:transition: (optional, once) Transition for gallery - image level
|
||||
:class: (optional, once) HTML class for gallery - node level
|
||||
|
||||
Title, thumbnail size and description are same for all
|
||||
images defined by the directive. If you need separated
|
||||
descriptions and titles, just use the directive several
|
||||
times with the same galleria name. In this case, theme
|
||||
html class and transition must be defined only in
|
||||
one directive.
|
||||
Image level options are same for all images defined by
|
||||
the directive. If you need separated descriptions and
|
||||
titles, just use the directive several times with the
|
||||
same galleria name. In this case, node level options
|
||||
must be defined only once.
|
||||
|
||||
Thumbnail size is in "WIDTHxHEIGHT" format, resulting
|
||||
image keeps ratio.
|
||||
|
||||
The first image of a gallery is displayed if javascript
|
||||
is not available on the browser.
|
||||
|
||||
Licensing
|
||||
~~~~~~~~~
|
||||
|
||||
|
|
2
setup.py
2
setup.py
|
@ -17,7 +17,7 @@ setup(
|
|||
package_data={
|
||||
"sphinx_galleria": [
|
||||
"*.py",
|
||||
"static/sphinxgalleria/*.js",
|
||||
"static/sphinxgalleria/*.mjs",
|
||||
"static/sphinxgalleria/*.css",
|
||||
]
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Create image galleries with GalleriaJS
|
||||
Create image galleries
|
||||
"""
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
|
@ -39,8 +39,28 @@ def copy_images_files(app: Sphinx, env: BuildEnvironment) -> None:
|
|||
ensuredir(os.path.dirname(dest))
|
||||
|
||||
with Image.open(original) as im:
|
||||
im.thumbnail(thumbsize)
|
||||
im.save(dest, "JPEG")
|
||||
if im.size[0]/im.size[1] > thumbsize[0]/thumbsize[1]:
|
||||
out = im.resize((
|
||||
thumbsize[0],
|
||||
thumbsize[1]
|
||||
), box=(
|
||||
(im.size[0]-thumbsize[1]*im.size[0]/thumbsize[0])//2,
|
||||
0,
|
||||
(im.size[0]+thumbsize[1]*im.size[0]/thumbsize[0])//2,
|
||||
im.size[1]
|
||||
))
|
||||
else:
|
||||
out = im.resize((
|
||||
thumbsize[0],
|
||||
thumbsize[1]
|
||||
), box=(
|
||||
0,
|
||||
(im.size[1]-thumbsize[0]*im.size[1]/thumbsize[0])//2,
|
||||
im.size[0],
|
||||
(im.size[1]+thumbsize[0]*im.size[1]/thumbsize[0])//2,
|
||||
))
|
||||
|
||||
out.save(dest, "JPEG")
|
||||
|
||||
|
||||
def install_static_files(app: Sphinx, env: BuildEnvironment) -> None:
|
||||
|
@ -69,12 +89,16 @@ def install_static_files(app: Sphinx, env: BuildEnvironment) -> None:
|
|||
|
||||
copyfile(source_path, static_path)
|
||||
|
||||
if static.endswith('.js'):
|
||||
app.add_js_file(os.path.join('sphinxgalleria', static))
|
||||
elif static.endswith('.css'):
|
||||
if static.endswith('.css'):
|
||||
app.add_css_file(os.path.join('sphinxgalleria', static))
|
||||
|
||||
|
||||
def init_directive(app: Sphinx, config) -> None:
|
||||
if 'galleria_override_image' in config and \
|
||||
config['galleria_override_image']:
|
||||
app.add_directive('image', directive.GalleriaDirective)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_node(
|
||||
directive.galleria,
|
||||
|
@ -88,6 +112,8 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||
)
|
||||
app.add_directive('galleria', directive.GalleriaDirective)
|
||||
app.add_env_collector(collector.GalleriaCollector)
|
||||
app.add_config_value('galleria_override_image', False, 'boolean')
|
||||
app.connect('env-updated', install_static_files)
|
||||
app.connect('env-updated', copy_images_files)
|
||||
app.connect('config-inited', init_directive)
|
||||
return {'version': __version__}
|
||||
|
|
|
@ -84,7 +84,7 @@ class GalleriaCollector(EnvironmentCollector):
|
|||
|
||||
images.append({
|
||||
'title': imageglob['title'],
|
||||
'description': imageglob['description'],
|
||||
'alt': imageglob['alt'],
|
||||
'thumb': os.path.relpath(
|
||||
thumb_path_jpg,
|
||||
app.env.srcdir),
|
||||
|
|
|
@ -17,6 +17,8 @@ from sphinx.writers.latex import LaTeXTranslator
|
|||
from sphinx.writers.texinfo import TexinfoTranslator
|
||||
from sphinx.writers.text import TextTranslator
|
||||
from sphinx.writers.manpage import ManualPageTranslator
|
||||
from sphinx.util.osutil import relative_uri
|
||||
from sphinx.locale import __
|
||||
|
||||
|
||||
class galleria(nodes.General, nodes.Element):
|
||||
|
@ -27,15 +29,30 @@ def html_visit_galleria(self: HTMLTranslator, node: galleria) -> None:
|
|||
galleria_id = 'galleria-%s' % uuid.uuid4()
|
||||
|
||||
self.body.append(
|
||||
"<div id='%s' class='%s'></div>" % (
|
||||
"<div id='%s' class='%s' width='%s' height='%s'>" % (
|
||||
galleria_id,
|
||||
node['class']
|
||||
node['class'] + ' align-%s' % node['options']['align'],
|
||||
node['options']['width'],
|
||||
node['options']['height'],
|
||||
)
|
||||
)
|
||||
|
||||
if len(node['images']) > 0:
|
||||
self.body.append("<figure><div class='row'>")
|
||||
self.body.append("<img src='%s' title='%s' alt='%s'>" % (
|
||||
node['images'][0]['image'],
|
||||
node['images'][0]['title'],
|
||||
node['images'][0]['alt']
|
||||
))
|
||||
self.body.append('</div></figure>')
|
||||
|
||||
self.body.append(
|
||||
"<script>document.addEventListener('ready', function() {" +
|
||||
"SphinxGalleria.run('%s', %s, dataSource=%s).init()});</script>" % (
|
||||
"</div><script type='module'>" +
|
||||
"import {SphinxGalleria} from './%s';\n" %
|
||||
relative_uri(
|
||||
self.builder.get_target_uri(self.builder.current_docname),
|
||||
'_static/sphinxgalleria/sphinxgalleria.mjs') +
|
||||
"new SphinxGalleria('%s', %s, %s).init();</script>" % (
|
||||
galleria_id,
|
||||
json.dumps(node['options']),
|
||||
json.dumps(node['images'])
|
||||
|
@ -47,66 +64,84 @@ def html_visit_galleria(self: HTMLTranslator, node: galleria) -> None:
|
|||
|
||||
def latex_visit_galleria(self: LaTeXTranslator, node: galleria) -> None:
|
||||
for image in node['images']:
|
||||
self.body.append('[%s]' % image['description'])
|
||||
self.body.append('[%s]' % image['alt'])
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
def texinfo_visit_galleria(self: TexinfoTranslator, node: galleria) -> None:
|
||||
for image in node['images']:
|
||||
self.body.append('[%s]' % image['description'])
|
||||
self.body.append('[%s]' % image['alt'])
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
def text_visit_galleria(self: TextTranslator, node: galleria) -> None:
|
||||
for image in node['images']:
|
||||
self.body.append('[%s]' % image['description'])
|
||||
self.body.append('[%s]' % image['alt'])
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
def gemini_visit_galleria(self, node: galleria) -> None:
|
||||
for image in node['images']:
|
||||
self.body.append('=> %s %s' % (image['path'], image['description']))
|
||||
self.body.append('=> %s %s' % (image['path'], image['alt']))
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
def man_visit_galleria(self: ManualPageTranslator, node: galleria) -> None:
|
||||
if 'description' in node.attributes:
|
||||
self.body.append('[%s]' % node['description'])
|
||||
if 'alt' in node.attributes:
|
||||
self.body.append('[%s]' % node['alt'])
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
def align_choices(argument):
|
||||
return directives.choice(argument, ('left', 'right', 'center'))
|
||||
|
||||
|
||||
class GalleriaDirective(Directive):
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
final_argument_whitespace = True
|
||||
|
||||
option_spec = {
|
||||
"class": directives.unchanged,
|
||||
"class": directives.class_option,
|
||||
"galleria": directives.unchanged,
|
||||
"description": directives.unchanged,
|
||||
"alt": directives.unchanged,
|
||||
"title": directives.unchanged,
|
||||
"thumbsize": directives.unchanged,
|
||||
"transition": directives.unchanged,
|
||||
'width': directives.length_or_percentage_or_unitless,
|
||||
'height': directives.length_or_unitless,
|
||||
'align': align_choices,
|
||||
'hide_title': directives.flag,
|
||||
'hide_alt': directives.flag,
|
||||
}
|
||||
|
||||
def run(self):
|
||||
if not self.state.document.hasattr('galleria_nodes'):
|
||||
self.state.document.galleria_nodes = {}
|
||||
source = self.state.document.settings._source
|
||||
document = self.state.document
|
||||
if not document.hasattr('galleria_nodes'):
|
||||
document.galleria_nodes = {}
|
||||
if source not in document.galleria_nodes:
|
||||
document.galleria_nodes[source] = {}
|
||||
|
||||
galleria_name = self.options.get('galleria')
|
||||
galleria_name = self.options.get('galleria') or uuid.uuid4()
|
||||
created = False
|
||||
|
||||
if galleria_name and \
|
||||
galleria_name in self.state.document.galleria_nodes:
|
||||
node = self.state.document.galleria_nodes[galleria_name]
|
||||
if galleria_name in document.galleria_nodes[source]:
|
||||
node = document.galleria_nodes[source][galleria_name]
|
||||
|
||||
else:
|
||||
node = galleria()
|
||||
node['class'] = 'galleria'
|
||||
node['options'] = {
|
||||
'transition': 'fade'
|
||||
'transition': 'fade',
|
||||
'label_prev': __('Previous'),
|
||||
'label_next': __('Next'),
|
||||
'label_close': __('Close'),
|
||||
'label_thumbnail': __('Thumbnail, click to enlarge'),
|
||||
}
|
||||
node['images'] = []
|
||||
document.galleria_nodes[source][galleria_name] = node
|
||||
|
||||
created = True
|
||||
|
||||
|
@ -115,12 +150,18 @@ class GalleriaDirective(Directive):
|
|||
if self.options.get('transition'):
|
||||
node['options']['transition'] = self.options['transition']
|
||||
|
||||
node['options']["width"] = self.options.get('width') or 'auto'
|
||||
node['options']["height"] = self.options.get('height') or 'auto'
|
||||
node['options']["align"] = self.options.get('align') or 'center'
|
||||
|
||||
images_path = self.arguments
|
||||
for path in images_path:
|
||||
image = {}
|
||||
image["description"] = self.options.get('description')
|
||||
image["alt"] = self.options.get('alt')
|
||||
image["title"] = self.options.get('title')
|
||||
image["thumbsize"] = self.options.get('thumbsize') or '100x100'
|
||||
image["hide_alt"] = bool(self.options.get('hide_alt'))
|
||||
image["hide_title"] = bool(self.options.get('hide_title'))
|
||||
image["image"] = path
|
||||
node['images'].append(image)
|
||||
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
.sphinxgalleria-core {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core.align-center {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core.align-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core.align-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure .row {
|
||||
flex-flow: row nowrap;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure .row button {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure .row button.button-modal {
|
||||
flex-grow: 1000;
|
||||
flex-shrink: 1000;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure .row button.button-modal .caption {
|
||||
background-color: hsl(0, 0%, 34%);
|
||||
color: white;
|
||||
text-transform: none;
|
||||
border-bottom-left-radius: .5rem;
|
||||
border-bottom-right-radius: .5rem;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: .5rem 1.5rem .5rem 1.5rem;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure .row button.button-modal figcaption {
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure .row button.button-modal img {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
width: auto;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure input[type=range] {
|
||||
width: 100%;
|
||||
height: 1.5rem;
|
||||
border: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
.sphinxgalleria-core figure input[type=range]:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
.sphinxgalleria-core figure input[type=range]::-webkit-slider-runnable-track {
|
||||
width: 100%;
|
||||
height: .1rem;
|
||||
padding: 0 1rem 0 1rem;
|
||||
margin: 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
animate: 0.2s;
|
||||
background-color: hsl(0, 0%, 34%);
|
||||
}
|
||||
.sphinxgalleria-core figure input[type=range]::-webkit-slider-thumb {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
border-radius: .5rem;
|
||||
border: none;
|
||||
background-color: hsl(0, 0%, 34%);
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
margin-top: -.5rem;
|
||||
}
|
||||
.sphinxgalleria-core figure input[type=range]:focus::-webkit-slider-runnable-track {
|
||||
background-color: hsl(0, 0%, 34%);
|
||||
border: none;
|
||||
}
|
||||
.sphinxgalleria-core figure input[type=range]::-moz-range-track {
|
||||
width: 100%;
|
||||
padding: 0 1rem 0 1rem;
|
||||
margin: 0;
|
||||
border: none;
|
||||
height: .1rem;
|
||||
cursor: pointer;
|
||||
animate: 0.2s;
|
||||
background-color: hsl(0, 0%, 34%);
|
||||
}
|
||||
.sphinxgalleria-core figure input[type=range]::-moz-range-thumb {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
border-radius: .5rem;
|
||||
background-color: hsl(0, 0%, 34%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core .mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: hsla(0, 0%, 0%, 80%);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core .submask {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog {
|
||||
position: absolute;
|
||||
top: 3vh;
|
||||
left: 0;
|
||||
height: 90vh;
|
||||
max-height: 90vh;
|
||||
width: max-content;
|
||||
margin: 0 auto 0 auto;
|
||||
padding-left: 3rem;
|
||||
padding-right: 3rem;
|
||||
background-color: black;
|
||||
color: white;
|
||||
border: white solid 0.2rem;
|
||||
border-radius: 0.5rem;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog img {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
object-fit: contain;
|
||||
flex-grow: 1000;
|
||||
flex-shrink: 1000;
|
||||
margin: 0.5rem 0 0.5rem 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog menu {
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog button {
|
||||
border: none;
|
||||
padding: .5em;
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog button:hover,
|
||||
.sphinxgalleria-core dialog button:focus {
|
||||
background-color: hsl(0, 0%, 34%);
|
||||
transition: background-color ease 0.4s;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog header button {
|
||||
position: absolute;
|
||||
top: .5rem;
|
||||
right: -.5rem;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog header button::after {
|
||||
content: '✕';
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog header {
|
||||
position: relative;
|
||||
min-height: 3rem;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog menu {
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog header::after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core dialog menu button.close {
|
||||
float: right;
|
||||
}
|
||||
.sphinxgalleria-core dialog menu button.close::before {
|
||||
margin-right: 0.5rem;
|
||||
content: '✕';
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure button.prev,
|
||||
.sphinxgalleria-core figure button.next {
|
||||
background-color: hsl(0, 0%, 34%);
|
||||
color: white;
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
margin: auto .5rem auto .5rem;
|
||||
border-radius: 1rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure button.prev:hover,
|
||||
.sphinxgalleria-core figure button.next:hover,
|
||||
.sphinxgalleria-core figure button.prev:focus,
|
||||
.sphinxgalleria-core figure button.next:focus {
|
||||
background-color: hsl(0, 0%, 64%);
|
||||
transition: background-color ease .4s;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure button.prev {
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure button.next {
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure button.prev::before,
|
||||
.sphinxgalleria-core dialog menu button.prev::before {
|
||||
margin-right: 0.5rem;
|
||||
content: '←';
|
||||
}
|
||||
|
||||
.sphinxgalleria-core figure button.next::after,
|
||||
.sphinxgalleria-core dialog menu button.next::after {
|
||||
margin-left: 0.5rem;
|
||||
content: '→';
|
||||
}
|
||||
|
||||
.sphinxgalleria-core ul.thumbnails {
|
||||
overflow-x: hidden;
|
||||
margin: 0 auto 0 auto;
|
||||
padding: 0;
|
||||
max-width: 100%;
|
||||
height: max-content;
|
||||
display: inline-flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core ul.thumbnails li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core ul.thumbnails li input[type=radio] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core ul.thumbnails li input:checked + label {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.sphinxgalleria-core ul.thumbnails li img {
|
||||
margin: 0.5rem;
|
||||
cursor: pointer;
|
||||
max-width: unset;
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
class SphinxGalleria {
|
||||
constructor(target, options, data) {
|
||||
var self = this;
|
||||
self.target = target;
|
||||
self.options = options;
|
||||
self.data = data;
|
||||
|
||||
self.node_target = null;
|
||||
self.node_figure = document.createElement('figure');
|
||||
self.node_image = document.createElement('img');
|
||||
self.node_caption = document.createElement('figcaption');
|
||||
self.node_thumbnails = document.createElement('div');
|
||||
self.node_dialog = document.createElement('dialog', modal=true);
|
||||
|
||||
var button_prev = document.createElement('button', id=self.target+"-prev")
|
||||
var button_next = document.createElement('button', id=self.target+"-next")
|
||||
button_prev.appendChild(document.createTextNode('<'));
|
||||
button_next.appendChild(document.createTextNode('>'));
|
||||
|
||||
button_prev.onkeypress = self.onprev
|
||||
button_prev.onclick = self.onprev
|
||||
|
||||
button_next.onkeypress = self.onnext
|
||||
button_.onclick = self.onnext
|
||||
|
||||
self.node_figure.appendChild(self.node_image);
|
||||
self.node_figure.appendChild(button_prev);
|
||||
self.node_figure.appendChild(button_next);
|
||||
self.node_figure.appendChild(self.node_caption);
|
||||
}
|
||||
|
||||
init() {
|
||||
var self = this;
|
||||
self.node_target = document.getElementById(self.target);
|
||||
self.node_target.innerHTML = '';
|
||||
self.node_target.appendChild(self.node_figure);
|
||||
self.node_target.appendChild(self.node_thumbnails);
|
||||
self.node_target.appendChild(self.node_dialog);
|
||||
}
|
||||
|
||||
onprev(event) {
|
||||
var key = event.keyCode || event.charCode || event.which;
|
||||
if(event.type==='keypress' && key!==13 && key!==32) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
onnext(event) {
|
||||
var key = event.keyCode || event.charCode || event.which;
|
||||
if(event.type==='keypress' && key!==13 && key!==32) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
changeImage() {
|
||||
}
|
||||
}
|
368
sphinx_galleria/static/sphinxgalleria/sphinxgalleria.mjs
Normal file
368
sphinx_galleria/static/sphinxgalleria/sphinxgalleria.mjs
Normal file
|
@ -0,0 +1,368 @@
|
|||
"use strict()";
|
||||
|
||||
export class SphinxGalleria {
|
||||
constructor(target, options, data) {
|
||||
var self = this;
|
||||
self.target = target;
|
||||
self.options = options;
|
||||
self.data = data;
|
||||
self.oneimage = self.data.length === 1;
|
||||
|
||||
self.node_target = null;
|
||||
self.node_figure = document.createElement('figure');
|
||||
self.button_modal = document.createElement('button');
|
||||
self.button_modal.setAttribute('aria-haspopup', 'dialog');
|
||||
self.button_modal.setAttribute('class', 'button-modal');
|
||||
|
||||
self.node_image = document.createElement('img');
|
||||
self.node_caption = document.createElement('figcaption');
|
||||
self.node_alt = document.createElement('p');
|
||||
self.node_alt.setAttribute('id', self.target+'-'+'alt');
|
||||
self.node_image.setAttribute('aria-describedby', self.target+'-'+'alt');
|
||||
self.node_thumbnails = document.createElement('ul');
|
||||
self.node_thumbnails.setAttribute('class', 'thumbnails');
|
||||
self.node_dialog = document.createElement('dialog');
|
||||
self.node_mask = document.createElement('div');
|
||||
self.node_mask.setAttribute('class', 'mask');
|
||||
self.node_mask.hidden = true;
|
||||
var node_submask = document.createElement('div');
|
||||
node_submask.setAttribute('class', 'submask');
|
||||
|
||||
self.node_div_caption = document.createElement('div');
|
||||
self.node_div_caption.setAttribute('class', 'caption');
|
||||
|
||||
var figure_row = document.createElement('div');
|
||||
figure_row.setAttribute('class', 'row');
|
||||
|
||||
self.dialog_button_close = document.createElement('button');
|
||||
self.dialog_button_close.setAttribute('class', 'close');
|
||||
|
||||
self.dialog_button_close_icon = document.createElement('button');
|
||||
self.dialog_button_close_icon.setAttribute('aria-label', self.options.label_close);
|
||||
|
||||
self.dialog_image = document.createElement('img');
|
||||
self.dialog_image.setAttribute('aria-describedby', self.target+'-'+'alt');
|
||||
|
||||
self.dialog_title = document.createElement('h1');
|
||||
var dialog_header = document.createElement('header');
|
||||
var dialog_menu = document.createElement('menu');
|
||||
|
||||
if(self.oneimage) {
|
||||
self.node_thumbnails.hidden = true;
|
||||
self.node_thumbnails.setAttribute('aria-hidden', true);
|
||||
self.node_thumbnails.style.visibility = 'hidden';
|
||||
} else {
|
||||
self.node_slider = document.createElement('input');
|
||||
self.node_slider.setAttribute('type', 'range');
|
||||
self.node_slider.setAttribute('min', 1);
|
||||
self.node_slider.setAttribute('max', self.data.length);
|
||||
self.node_slider.setAttribute('value', 1);
|
||||
|
||||
self.button_prev = document.createElement('button');
|
||||
self.button_prev.setAttribute('class', 'prev');
|
||||
self.button_prev.setAttribute('aria-label', self.options.label_prev);
|
||||
|
||||
self.button_next = document.createElement('button');
|
||||
self.button_next.setAttribute('class', 'next');
|
||||
self.button_next.setAttribute('aria-label', self.options.label_next);
|
||||
|
||||
self.dialog_button_prev = document.createElement('button');
|
||||
self.dialog_button_prev.setAttribute('class', 'prev');
|
||||
self.dialog_button_next = document.createElement('button');
|
||||
self.dialog_button_next.setAttribute('class', 'next');
|
||||
self.dialog_button_prev.appendChild(document.createTextNode(self.options.label_prev));
|
||||
self.dialog_button_next.appendChild(document.createTextNode(self.options.label_next));
|
||||
|
||||
figure_row.appendChild(self.button_prev);
|
||||
dialog_menu.appendChild(self.dialog_button_prev);
|
||||
dialog_menu.appendChild(self.dialog_button_next);
|
||||
}
|
||||
|
||||
node_submask.appendChild(self.node_dialog);
|
||||
self.node_mask.appendChild(node_submask);
|
||||
|
||||
figure_row.appendChild(self.button_modal);
|
||||
self.node_figure.appendChild(figure_row);
|
||||
|
||||
self.node_div_caption.appendChild(self.node_caption);
|
||||
self.node_div_caption.appendChild(self.node_alt);
|
||||
self.button_modal.appendChild(self.node_image);
|
||||
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_button_close_icon);
|
||||
self.node_dialog.appendChild(dialog_header);
|
||||
self.node_dialog.appendChild(self.dialog_image);
|
||||
dialog_menu.appendChild(self.dialog_button_close);
|
||||
self.node_dialog.appendChild(dialog_menu);
|
||||
|
||||
if(!self.oneimage) {
|
||||
figure_row.appendChild(self.button_next);
|
||||
self.node_figure.appendChild(self.node_slider);
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
var self = this;
|
||||
self.node_target = document.getElementById(self.target);
|
||||
self.node_target.innerHTML = '';
|
||||
self.node_target.setAttribute(
|
||||
'class',
|
||||
self.node_target.getAttribute('class') + " sphinxgalleria-core"
|
||||
);
|
||||
self.node_target.appendChild(self.node_figure);
|
||||
self.node_target.appendChild(self.node_thumbnails);
|
||||
self.node_target.appendChild(self.node_mask);
|
||||
|
||||
var onmodal = function(event) {
|
||||
var key = event.keyCode || event.charCode || event.which;
|
||||
if(event.type==='keypress' && key!==13 && key!==32) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
self.showModal();
|
||||
};
|
||||
self.button_modal.addEventListener('click', onmodal);
|
||||
self.button_modal.addEventListener('keypress', onmodal);
|
||||
|
||||
var onclose = function(event) {
|
||||
var key = event.keyCode || event.charCode || event.which;
|
||||
if(event.type==='keypress' && key!==13 && key!==32) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
self.closeModal();
|
||||
};
|
||||
|
||||
self.node_mask.addEventListener('click', onclose);
|
||||
self.node_dialog.addEventListener('click', function(e) {e.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('keypress', onclose);
|
||||
|
||||
if(!self.oneimage) {
|
||||
var onprev = function(event) {
|
||||
var key = event.keyCode || event.charCode || event.which;
|
||||
if(event.type==='keypress' && key!==13 && key!==32) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
self.prev();
|
||||
};
|
||||
|
||||
var onnext = function(event) {
|
||||
var key = event.keyCode || event.charCode || event.which;
|
||||
if(event.type==='keypress' && key!==13 && key!==32) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
self.next();
|
||||
};
|
||||
|
||||
self.button_prev.addEventListener('keypress', onprev);
|
||||
self.button_prev.addEventListener('click', onprev);
|
||||
|
||||
self.button_next.addEventListener('keypress', onnext);
|
||||
self.button_next.addEventListener('click', onnext);
|
||||
|
||||
self.dialog_button_prev.addEventListener('keypress', onprev);
|
||||
self.dialog_button_prev.addEventListener('click', onprev);
|
||||
|
||||
self.dialog_button_next.addEventListener('keypress', onnext);
|
||||
self.dialog_button_next.addEventListener('click', onnext);
|
||||
|
||||
self.dialog_image.addEventListener('click', function(e) {
|
||||
var x = e.layerX - e.target.x;
|
||||
if(x < e.target.width/2) {
|
||||
self.prev();
|
||||
e.preventDefault();
|
||||
} else if(x > e.target.width/2) {
|
||||
self.next();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
self.node_slider.addEventListener('change', function() {
|
||||
var idx = self.node_slider.value - 1;
|
||||
self.node_thumbnails.querySelector('input[data-index="'+idx+'"]').click();
|
||||
});
|
||||
}
|
||||
|
||||
self.data.forEach(function(image_data, idx) {
|
||||
var image_element = document.createElement('li');
|
||||
var image_button = document.createElement('input');
|
||||
image_button.setAttribute('type', 'radio');
|
||||
image_button.setAttribute('value', image_data.image);
|
||||
image_button.setAttribute('name', self.target);
|
||||
image_button.setAttribute('data-index', idx);
|
||||
image_button.setAttribute('id', self.target+'-'+idx);
|
||||
if(idx===0) {
|
||||
image_button.checked = true;
|
||||
}
|
||||
|
||||
image_element.appendChild(image_button);
|
||||
|
||||
var image_label = document.createElement('label');
|
||||
image_label.setAttribute('for', self.target+'-'+idx);
|
||||
image_element.appendChild(image_label);
|
||||
|
||||
var image_thumb = document.createElement('img');
|
||||
image_thumb.setAttribute('src', image_data.thumb);
|
||||
|
||||
if(image_data.alt) {
|
||||
image_button.setAttribute('data-alt', image_data.alt);
|
||||
image_thumb.setAttribute('alt', image_data.alt);
|
||||
} else {
|
||||
image_thumb.setAttribute('alt', self.options.label_thumbnail);
|
||||
}
|
||||
|
||||
if(image_data.title) {
|
||||
image_button.setAttribute('data-title', image_data.title);
|
||||
}
|
||||
if(image_data.hide_alt) {
|
||||
image_button.setAttribute('data-hide-alt', true);
|
||||
}
|
||||
if(image_data.hide_alt) {
|
||||
image_button.setAttribute('data-hide-title', true);
|
||||
}
|
||||
|
||||
if(image_data.transition) {
|
||||
image_thumb.setAttribute('data-transition', image_data.transition);
|
||||
}
|
||||
|
||||
image_label.appendChild(image_thumb);
|
||||
self.node_thumbnails.appendChild(image_element);
|
||||
|
||||
image_button.addEventListener('change', function() {self.changeImage();});
|
||||
});
|
||||
|
||||
self.node_target.addEventListener('keypress', function(event) {
|
||||
var key = event.keyCode || event.charCode || event.which;
|
||||
|
||||
if(!self.oneimage && key===37) {
|
||||
self.prev();
|
||||
} else if(!self.oneimage && key===39) {
|
||||
self.next();
|
||||
} else if(key===27) {
|
||||
self.closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
self.changeImage();
|
||||
}
|
||||
|
||||
prev() {
|
||||
var self = this;
|
||||
if(!self.oneimage) {
|
||||
var idx = self.node_thumbnails.querySelector('input:checked').getAttribute('data-index');
|
||||
idx = parseInt(idx) - 1;
|
||||
if(idx < 0) {
|
||||
idx = self.data.length - 1;
|
||||
}
|
||||
document.getElementById(self.target+'-'+idx).checked = true;
|
||||
self.changeImage();
|
||||
}
|
||||
}
|
||||
|
||||
next() {
|
||||
var self = this;
|
||||
if(!self.oneimage) {
|
||||
var idx = self.node_thumbnails.querySelector('input:checked').getAttribute('data-index');
|
||||
idx = parseInt(idx) + 1;
|
||||
if(idx > self.data.length - 1) {
|
||||
idx = 0;
|
||||
}
|
||||
document.getElementById(self.target+'-'+idx).checked = true;
|
||||
self.changeImage();
|
||||
}
|
||||
}
|
||||
|
||||
changeImage() {
|
||||
var self = this;
|
||||
var current = self.node_thumbnails.querySelector('input:checked');
|
||||
var title = current.getAttribute('data-title');
|
||||
var alt = current.getAttribute('data-alt');
|
||||
var hide_title = current.hasAttribute('data-hide-title');
|
||||
var hide_alt = current.hasAttribute('data-hide-alt');
|
||||
var url = current.getAttribute('value');
|
||||
var hide_caption = true;
|
||||
var idx = parseInt(current.getAttribute('data-index'));
|
||||
|
||||
if(!self.oneimage) {
|
||||
if(self.node_slider.value !== idx+1) {
|
||||
self.node_slider.value = idx + 1;
|
||||
}
|
||||
var current_img = current.nextSibling.childNodes[0];
|
||||
self.node_thumbnails.scrollTo({
|
||||
left: current_img.x -
|
||||
self.node_thumbnails.offsetWidth/2 +
|
||||
current_img.clientWidth/2,
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
|
||||
if(!hide_title && title) {
|
||||
self.node_caption.innerHTML = title;
|
||||
self.node_caption.hidden = false;
|
||||
self.dialog_title.innerHTML = title;
|
||||
self.dialog_title.hidden = false;
|
||||
hide_caption = false;
|
||||
} else if(title) {
|
||||
self.node_caption.innerHTML = '';
|
||||
self.node_caption.hidden = true;
|
||||
self.dialog_title.innerHTML = title;
|
||||
self.dialog_title.hidden = false;
|
||||
} else {
|
||||
self.node_caption.innerHTML = '';
|
||||
self.node_caption.hidden = true;
|
||||
self.dialog_title.innerHTML = '';
|
||||
self.dialog_title.hidden = true;
|
||||
}
|
||||
|
||||
if(!hide_alt && alt) {
|
||||
self.node_alt.innerHTML = alt;
|
||||
self.node_alt.hidden = false;
|
||||
hide_caption = false;
|
||||
} else {
|
||||
self.node_alt.innerHTML = '';
|
||||
self.node_alt.hidden = true;
|
||||
}
|
||||
|
||||
if(hide_caption) {
|
||||
self.node_div_caption.hidden = true;
|
||||
} else {
|
||||
self.node_div_caption.hidden = false;
|
||||
}
|
||||
|
||||
self.node_image.setAttribute('src', url);
|
||||
self.dialog_image.setAttribute('src', url);
|
||||
}
|
||||
|
||||
showModal() {
|
||||
this.node_mask.hidden = false;
|
||||
if(this.node_dialog.showModal) {
|
||||
this.node_dialog.showModal();
|
||||
} else {
|
||||
this.node_dialog.open = true;
|
||||
this.node_dialog.setAttribute('open', true);
|
||||
this.node_dialog.setAttribute('aria-modal', true);
|
||||
this.node_dialog.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
closeModal() {
|
||||
if(this.node_dialog.showModal) {
|
||||
this.node_dialog.close();
|
||||
} else {
|
||||
this.node_dialog.open = false;
|
||||
this.node_dialog.removeAttribute('open');
|
||||
this.node_dialog.removeAttribute('aria-modal');
|
||||
this.node_dialog.hidden = true;
|
||||
}
|
||||
this.node_mask.hidden = true;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue