diff --git a/README.rst b/README.rst
index 14c2644..0f223fd 100644
--- a/README.rst
+++ b/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
~~~~~~~~~
diff --git a/setup.py b/setup.py
index 296d206..d53f634 100644
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,7 @@ setup(
package_data={
"sphinx_galleria": [
"*.py",
- "static/sphinxgalleria/*.js",
+ "static/sphinxgalleria/*.mjs",
"static/sphinxgalleria/*.css",
]
},
diff --git a/sphinx_galleria/__init__.py b/sphinx_galleria/__init__.py
index 15d91b6..68b378d 100644
--- a/sphinx_galleria/__init__.py
+++ b/sphinx_galleria/__init__.py
@@ -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__}
diff --git a/sphinx_galleria/collector.py b/sphinx_galleria/collector.py
index e253e3c..01d551f 100644
--- a/sphinx_galleria/collector.py
+++ b/sphinx_galleria/collector.py
@@ -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),
diff --git a/sphinx_galleria/directive.py b/sphinx_galleria/directive.py
index 0ce7011..77f0158 100644
--- a/sphinx_galleria/directive.py
+++ b/sphinx_galleria/directive.py
@@ -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(
- "
" % (
+ "" % (
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("
")
+ self.body.append("
" % (
+ node['images'][0]['image'],
+ node['images'][0]['title'],
+ node['images'][0]['alt']
+ ))
+ self.body.append('
')
+
self.body.append(
- "" % (
+ "
" % (
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)
diff --git a/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.css b/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.css
index e69de29..ce8d94c 100644
--- a/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.css
+++ b/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.css
@@ -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;
+}
diff --git a/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.js b/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.js
deleted file mode 100644
index adc3f0e..0000000
--- a/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.js
+++ /dev/null
@@ -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() {
- }
-}
diff --git a/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.mjs b/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.mjs
new file mode 100644
index 0000000..a80ebd7
--- /dev/null
+++ b/sphinx_galleria/static/sphinxgalleria/sphinxgalleria.mjs
@@ -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;
+ }
+}