boxesserver: refactor
* move & refactor JS to static * add some typing * move `head` to functions for reusability * fix wrong separator for `hreflang` value * fix various html validator errors
This commit is contained in:
parent
673838d563
commit
4ef6c5c5ae
|
@ -28,7 +28,6 @@ import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Any, NoReturn
|
from typing import Any, NoReturn
|
||||||
from urllib.parse import parse_qs
|
|
||||||
from urllib.parse import unquote_plus, quote
|
from urllib.parse import unquote_plus, quote
|
||||||
from wsgiref.simple_server import make_server
|
from wsgiref.simple_server import make_server
|
||||||
|
|
||||||
|
@ -187,29 +186,6 @@ class BServer:
|
||||||
|
|
||||||
return row % input
|
return row % input
|
||||||
|
|
||||||
scripts = """
|
|
||||||
<script>
|
|
||||||
function showHide(id) {
|
|
||||||
var e = document.getElementById(id);
|
|
||||||
var h = document.getElementById("h-" + id);
|
|
||||||
if(e.style.display == null || e.style.display == "none") {
|
|
||||||
e.style.display = "block";
|
|
||||||
h.classList.add("open");
|
|
||||||
h.setAttribute("aria-expanded","true");
|
|
||||||
} else {
|
|
||||||
e.style.display = "none";
|
|
||||||
h.classList.remove("open");
|
|
||||||
h.setAttribute("aria-expanded","false");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function hideargs() {
|
|
||||||
for ( i=0; i<%i; i++) {
|
|
||||||
showHide(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
"""
|
|
||||||
|
|
||||||
def args2html_cached(self, name, box, lang, action="", defaults={}):
|
def args2html_cached(self, name, box, lang, action="", defaults={}):
|
||||||
if defaults == {}:
|
if defaults == {}:
|
||||||
key = (name, lang.info().get('language', None), action)
|
key = (name, lang.info().get('language', None), action)
|
||||||
|
@ -224,24 +200,18 @@ class BServer:
|
||||||
lang_name = lang.info().get('language', None)
|
lang_name = lang.info().get('language', None)
|
||||||
|
|
||||||
langparam = ""
|
langparam = ""
|
||||||
lang_attr = ""
|
|
||||||
if lang_name:
|
if lang_name:
|
||||||
langparam = "?language=" + lang_name
|
langparam = "?language=" + lang_name
|
||||||
lang_attr = f" lang=\"{lang_name}\""
|
|
||||||
|
|
||||||
result = [f"""<!DOCTYPE html>
|
result = [f"""{self.genHTMLStart(lang)}
|
||||||
<html{lang_attr}>
|
|
||||||
<head>
|
<head>
|
||||||
<title>{_("%s - Boxes") % _(name)}</title>
|
<title>{_("%s - Boxes") % _(name)}</title>
|
||||||
<meta charset="utf-8">
|
{self.genHTMLMeta()}
|
||||||
<link rel="icon" type="image/svg+xml" href="{self.static_url}/boxes-logo.svg" sizes="any">
|
|
||||||
<link rel="icon" type="image/x-icon" href="{self.static_url}/favicon.ico">
|
|
||||||
{self.genHTMLMetaLanguageLink()}
|
{self.genHTMLMetaLanguageLink()}
|
||||||
<link rel="stylesheet" href="{self.static_url}/self.css">
|
{self.genHTMLCSS()}
|
||||||
{self.scripts % (len(box.argparser._action_groups) - 3)}
|
{self.genHTMLJS()}
|
||||||
<meta name="flattr:id" content="456799">
|
|
||||||
</head>
|
</head>
|
||||||
<body onload="hideargs()">
|
<body onload="initPage({len(box.argparser._action_groups) - 3})">
|
||||||
|
|
||||||
<div class="container" style="background-color: #FFF8EA;">
|
<div class="container" style="background-color: #FFF8EA;">
|
||||||
<div style="float: left;">
|
<div style="float: left;">
|
||||||
|
@ -264,7 +234,7 @@ class BServer:
|
||||||
if len(group._group_actions) == 1 and isinstance(group._group_actions[0], argparse._HelpAction):
|
if len(group._group_actions) == 1 and isinstance(group._group_actions[0], argparse._HelpAction):
|
||||||
continue
|
continue
|
||||||
prefix = getattr(group, "prefix", None)
|
prefix = getattr(group, "prefix", None)
|
||||||
result.append(f'''<h3 id="h-{groupid}" role="button" aria-expanded="true" tabindex="0" class="open" onclick="showHide({groupid})" onkeypress="if(event.keyCode == 13) showHide({groupid})">{_(group.title)}</h3>\n<table role="presentation" id="{groupid}">\n''')
|
result.append(f'''<h3 id="h-{groupid}" data-id="{groupid}" role="button" aria-expanded="true" tabindex="0" class="toggle open">{_(group.title)}</h3>\n<table role="presentation" id="{groupid}">\n''')
|
||||||
|
|
||||||
for a in group._group_actions:
|
for a in group._group_actions:
|
||||||
if a.dest in ("input", "output"):
|
if a.dest in ("input", "output"):
|
||||||
|
@ -293,50 +263,33 @@ class BServer:
|
||||||
.replace('src="static/', f'src="{self.static_url}/'))
|
.replace('src="static/', f'src="{self.static_url}/'))
|
||||||
|
|
||||||
result.append(f'''<div>
|
result.append(f'''<div>
|
||||||
<img src="{self.static_url}/samples/{box.__class__.__name__}.jpg" width="100%" onerror="this.parentElement.innerHTML = '{no_img_msg}';">
|
<img style="width:100%;" src="{self.static_url}/samples/{box.__class__.__name__}.jpg" onerror="this.parentElement.innerHTML = '{no_img_msg}';" alt="Picture of box.">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{self.footer(lang)}</body>
|
{self.genPagePartFooter(lang)}
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
''')
|
''')
|
||||||
return (s.encode("utf-8") for s in result)
|
return (s.encode("utf-8") for s in result)
|
||||||
|
|
||||||
def menu(self, lang):
|
def genPageMenu(self, lang):
|
||||||
_ = lang.gettext
|
_ = lang.gettext
|
||||||
lang_name = lang.info().get('language', None)
|
lang_name = lang.info().get('language', None)
|
||||||
|
|
||||||
langparam = ""
|
langparam = ""
|
||||||
lang_attr = ""
|
|
||||||
if lang_name:
|
if lang_name:
|
||||||
langparam = "?language=" + lang_name
|
langparam = "?language=" + lang_name
|
||||||
lang_attr = f" lang=\"{lang_name}\""
|
|
||||||
|
|
||||||
result = [f"""<!DOCTYPE html>
|
result = [f"""{self.genHTMLStart(lang)}
|
||||||
<html{lang_attr}>
|
|
||||||
<head>
|
<head>
|
||||||
<title>{_("Boxes.py")}</title>
|
<title>{_("Boxes.py")}</title>
|
||||||
<meta charset="utf-8">
|
{self.genHTMLMeta()}
|
||||||
<link rel="icon" type="image/svg+xml" href="{self.static_url}/boxes-logo.svg" sizes="any">
|
|
||||||
<link rel="icon" type="image/x-icon" href="{self.static_url}/favicon.ico">
|
|
||||||
{self.genHTMLMetaLanguageLink()}
|
{self.genHTMLMetaLanguageLink()}
|
||||||
<link rel="stylesheet" href="{self.static_url}/self.css">
|
{self.genHTMLCSS()}
|
||||||
""",
|
{self.genHTMLJS()}
|
||||||
""" <script>
|
|
||||||
function change(group, img_link){
|
|
||||||
document.getElementById("sample-"+group).src = img_link;
|
|
||||||
document.getElementById("sample-"+group).style.height = "auto";
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeback(group){
|
|
||||||
document.getElementById("sample-" + group).src= "%s/nothing.png";
|
|
||||||
document.getElementById("sample-" + group).style.height= "0px";
|
|
||||||
}
|
|
||||||
""" % self.static_url,
|
|
||||||
f""" </script>{self.scripts % len(self.groups)}
|
|
||||||
<meta name="flattr:id" content="456799">
|
|
||||||
</head>
|
</head>
|
||||||
<body onload="hideargs()">
|
<body onload="initPage()">
|
||||||
<div class="container" style="background-color: #FFF8EA;">
|
<div class="container" style="background-color: #FFF8EA;">
|
||||||
<div style="width: 75%; float: left;">
|
<div style="width: 75%; float: left;">
|
||||||
<h1>{_("Boxes.py")}</h1>
|
<h1>{_("Boxes.py")}</h1>
|
||||||
|
@ -354,13 +307,20 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="menu" style="width: 100%">
|
<div class="menu" style="width: 100%">
|
||||||
|
<img style="width: 200px;" id="sample-preview" src="{self.static_url}/nothing.png" alt="">
|
||||||
"""]
|
"""]
|
||||||
for nr, group in enumerate(self.groups):
|
for nr, group in enumerate(self.groups):
|
||||||
result.append(f'''
|
result.append(f'''
|
||||||
<h3 id="h-{nr}" role="button" aria-expanded="false" class="open" tabindex="0" onclick="showHide('{nr}')" onkeypress="if(event.keyCode == 13) showHide('{nr}')"
|
<h3 id="h-{nr}"
|
||||||
onmouseenter="change('{group.name}', '{self.static_url}/samples/{group.thumbnail}')"
|
data-id="{nr}"
|
||||||
onmouseleave="changeback('{group.name}')">{_(group.title)}</h3>
|
data-thumbnail="{self.static_url}/samples/{group.thumbnail}"
|
||||||
<img style="width: 200px;" id="sample-{group.name}" src="{self.static_url}/nothing.png" alt="">
|
role="button"
|
||||||
|
aria-expanded="false"
|
||||||
|
class="toggle thumbnail open"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
{_(group.title)}
|
||||||
|
</h3>
|
||||||
<div id="{nr}"><ul>''')
|
<div id="{nr}"><ul>''')
|
||||||
for box in group.generators:
|
for box in group.generators:
|
||||||
name = box.__name__
|
name = box.__name__
|
||||||
|
@ -369,8 +329,7 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
docs = ""
|
docs = ""
|
||||||
if box.__doc__:
|
if box.__doc__:
|
||||||
docs = " - " + _(box.__doc__)
|
docs = " - " + _(box.__doc__)
|
||||||
result.append(f"""
|
result.append(f"""<li class="thumbnail" data-thumbnail="{self.static_url}/samples/{name}-thumb.jpg"><a href="{name}{langparam}">{_(name)}</a>{docs}</li>""")
|
||||||
<li onmouseenter="change('{group.name}', '{self.static_url}/samples/{name}-thumb.jpg')" onmouseleave="changeback('{group.name}')"><a href="{name}{langparam}">{_(name)}</a>{docs}</li>""")
|
|
||||||
result.append("\n</ul></div>\n")
|
result.append("\n</ul></div>\n")
|
||||||
result.append(f"""
|
result.append(f"""
|
||||||
</div>
|
</div>
|
||||||
|
@ -380,21 +339,44 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{self.footer(lang)}
|
{self.genPagePartFooter(lang)}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
""")
|
""")
|
||||||
return (s.encode("utf-8") for s in result)
|
return (s.encode("utf-8") for s in result)
|
||||||
|
|
||||||
|
def genHTMLStart(self, lang) -> str:
|
||||||
|
lang_attr = lang.info().get("language", "")
|
||||||
|
|
||||||
|
if lang_attr != "":
|
||||||
|
return f"""<!DOCTYPE html><html lang="{lang_attr.replace('_', '-')}">"""
|
||||||
|
|
||||||
|
return "<!DOCTYPE html><html>"
|
||||||
|
|
||||||
|
def genHTMLMeta(self) -> str:
|
||||||
|
return f'''
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="flattr:id" content="456799">
|
||||||
|
<link rel="icon" type="image/svg+xml" href="{self.static_url}/boxes-logo.svg" sizes="any">
|
||||||
|
<link rel="icon" type="image/x-icon" href="{self.static_url}/favicon.ico">
|
||||||
|
'''
|
||||||
|
|
||||||
def genHTMLMetaLanguageLink(self) -> str:
|
def genHTMLMetaLanguageLink(self) -> str:
|
||||||
"""Generates meta language list for search engines."""
|
"""Generates meta language list for search engines."""
|
||||||
languages = self.getLanguages()
|
languages = self.getLanguages()
|
||||||
|
|
||||||
s = ""
|
s = ""
|
||||||
for language in languages:
|
for language in languages:
|
||||||
s += f"<link rel='alternate' hreflang='{language}' href='https://www.festi.info/boxes.py/?language={language}'>\n"
|
s += f'<link rel="alternate" hreflang="{language.replace("_", "-")}" href="https://www.festi.info/boxes.py/?language={language}">\n'
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
def genHTMLCSS(self) -> str:
|
||||||
|
return f'<link rel="stylesheet" href="{self.static_url}/self.css">'
|
||||||
|
|
||||||
|
def genHTMLJS(self) -> str:
|
||||||
|
return f'<script src="{self.static_url}/self.js"></script>'
|
||||||
|
|
||||||
def genHTMLLanguageSelection(self, lang) -> str:
|
def genHTMLLanguageSelection(self, lang) -> str:
|
||||||
"""Generates a dropdown selection for the language change."""
|
"""Generates a dropdown selection for the language change."""
|
||||||
current_language = lang.info().get('language', '')
|
current_language = lang.info().get('language', '')
|
||||||
|
@ -415,7 +397,7 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
</form>
|
</form>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def footer(self, lang) -> str:
|
def genPagePartFooter(self, lang) -> str:
|
||||||
_ = lang.gettext
|
_ = lang.gettext
|
||||||
|
|
||||||
return """
|
return """
|
||||||
|
@ -430,19 +412,23 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def errorMessage(self, name, e, _):
|
def genPageError(self, name, e, lang) -> list[bytes]:
|
||||||
return [(f"""<html>
|
"""Generates a error page."""
|
||||||
|
_ = lang.gettext
|
||||||
|
|
||||||
|
h = f"""{self.genHTMLStart(lang)}
|
||||||
<head>
|
<head>
|
||||||
<title>{_("Error generating %s") % _(name)}</title>
|
<title>{_("Error generating %s") % _(name)}</title>
|
||||||
<meta name="flattr:id" content="456799">
|
{self.genHTMLMeta()}
|
||||||
|
<meta name="robots" content="noindex">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>{_("An error occurred!")}</h1>""" +
|
<h1>{_("An error occurred!")}</h1>
|
||||||
"".join("<p>%s</p>" % html.escape(s) for s in str(e).split("\n")) +
|
|
||||||
"""
|
"""
|
||||||
</body>
|
for s in str(e).split("\n"):
|
||||||
</html>
|
h += f"<p>{html.escape(s)}</p>\n"
|
||||||
""").encode("utf-8") ]
|
h += "</body></html>"
|
||||||
|
return [h.encode("utf-8")]
|
||||||
|
|
||||||
def serveStatic(self, environ, start_response):
|
def serveStatic(self, environ, start_response):
|
||||||
filename = environ["PATH_INFO"][len("/static/"):]
|
filename = environ["PATH_INFO"][len("/static/"):]
|
||||||
|
@ -501,10 +487,8 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
status = '200 OK'
|
status = '200 OK'
|
||||||
headers = [('Content-type', 'text/html; charset=utf-8'), ('X-XSS-Protection', '1; mode=block'), ('X-Content-Type-Options', 'nosniff'), ('x-frame-options', 'SAMEORIGIN'), ('Referrer-Policy', 'no-referrer')]
|
headers = [('Content-type', 'text/html; charset=utf-8'), ('X-XSS-Protection', '1; mode=block'), ('X-Content-Type-Options', 'nosniff'), ('x-frame-options', 'SAMEORIGIN'), ('Referrer-Policy', 'no-referrer')]
|
||||||
|
|
||||||
d = parse_qs(environ.get('QUERY_STRING', ''))
|
|
||||||
name = environ["PATH_INFO"][1:]
|
name = environ["PATH_INFO"][1:]
|
||||||
args = [unquote_plus(arg) for arg in
|
args = [unquote_plus(arg) for arg in environ.get('QUERY_STRING', '').split("&")]
|
||||||
environ.get('QUERY_STRING', '').split("&")]
|
|
||||||
render = "0"
|
render = "0"
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if arg.startswith("render="):
|
if arg.startswith("render="):
|
||||||
|
@ -519,7 +503,7 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
|
|
||||||
lang_name = lang.info().get('language', None)
|
lang_name = lang.info().get('language', None)
|
||||||
if lang_name not in self._cache:
|
if lang_name not in self._cache:
|
||||||
self._cache[lang_name] = list(self.menu(lang))
|
self._cache[lang_name] = list(self.genPageMenu(lang))
|
||||||
return self._cache[lang_name]
|
return self._cache[lang_name]
|
||||||
|
|
||||||
if name == "TrayLayout2":
|
if name == "TrayLayout2":
|
||||||
|
@ -536,13 +520,13 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
defaults[k] = html.escape(v, True)
|
defaults[k] = html.escape(v, True)
|
||||||
start_response(status, headers)
|
start_response(status, headers)
|
||||||
return self.args2html_cached(name, box, lang, "./" + name, defaults=defaults)
|
return self.args2html_cached(name, box, lang, "./" + name, defaults=defaults)
|
||||||
else:
|
|
||||||
args = ["--" + arg for arg in args if not arg.startswith("render=")]
|
args = ["--" + arg for arg in args if not arg.startswith("render=")]
|
||||||
try:
|
try:
|
||||||
box.parseArgs(args)
|
box.parseArgs(args)
|
||||||
except (ArgumentParserError) as e:
|
except ArgumentParserError as e:
|
||||||
start_response(status, headers)
|
start_response(status, headers)
|
||||||
return self.errorMessage(name, e, _)
|
return self.genPageError(name, e, lang)
|
||||||
if name == "TrayLayout":
|
if name == "TrayLayout":
|
||||||
start_response(status, headers)
|
start_response(status, headers)
|
||||||
box.fillDefault(box.x, box.y)
|
box.fillDefault(box.x, box.y)
|
||||||
|
@ -554,7 +538,7 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
box.parse(box.layout.split("\n"))
|
box.parse(box.layout.split("\n"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
start_response(status, headers)
|
start_response(status, headers)
|
||||||
return self.errorMessage(name, e, _)
|
return self.genPageError(name, e, lang)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fd, box.output = tempfile.mkstemp()
|
fd, box.output = tempfile.mkstemp()
|
||||||
|
@ -566,13 +550,10 @@ f""" </script>{self.scripts % len(self.groups)}
|
||||||
if not isinstance(e, ValueError):
|
if not isinstance(e, ValueError):
|
||||||
print("Exception during rendering:")
|
print("Exception during rendering:")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
start_response("500 Internal Server Error",
|
start_response("500 Internal Server Error", headers)
|
||||||
headers)
|
return self.genPageError(name, e, lang)
|
||||||
return self.errorMessage(name, e, _)
|
|
||||||
|
|
||||||
http_headers = box.formats.http_headers.get(
|
http_headers = box.formats.http_headers.get(box.format, [('Content-type', 'application/unknown; charset=utf-8')])[:]
|
||||||
box.format,
|
|
||||||
[('Content-type', 'application/unknown; charset=utf-8')])[:]
|
|
||||||
# Prevent crawlers.
|
# Prevent crawlers.
|
||||||
http_headers.append(('X-Robots-Tag', 'noindex,nofollow'))
|
http_headers.append(('X-Robots-Tag', 'noindex,nofollow'))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
function showThumbnail(img_link) {
|
||||||
|
const img = document.getElementById("sample-preview");
|
||||||
|
img.src = img_link;
|
||||||
|
img.style.height = "auto";
|
||||||
|
img.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
function showThumbnailEvt(evt) {
|
||||||
|
const url = evt.target.getAttribute("data-thumbnail");
|
||||||
|
showThumbnail(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideThumbnail() {
|
||||||
|
const img = document.getElementById("sample-preview");
|
||||||
|
img.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function toggleId(id) {
|
||||||
|
const e = document.getElementById(id);
|
||||||
|
const h = document.getElementById("h-" + id);
|
||||||
|
if (e.style.display == null || e.style.display === "none") {
|
||||||
|
e.style.display = "block";
|
||||||
|
h.classList.add("open");
|
||||||
|
h.setAttribute("aria-expanded", "true");
|
||||||
|
} else {
|
||||||
|
e.style.display = "none";
|
||||||
|
h.classList.remove("open");
|
||||||
|
h.setAttribute("aria-expanded", "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleEl(el) {
|
||||||
|
const id = el.getAttribute("data-id");
|
||||||
|
toggleId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleEvt(evt) {
|
||||||
|
const id = evt.target.getAttribute("data-id");
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role#examples
|
||||||
|
if (evt instanceof MouseEvent) {
|
||||||
|
toggleId(id);
|
||||||
|
}
|
||||||
|
if (evt instanceof KeyboardEvent && (evt.key === "Enter" || evt.key === " ")) {
|
||||||
|
evt.preventDefault();
|
||||||
|
toggleId(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initToggle(el, hide = false) {
|
||||||
|
// Add event handler.
|
||||||
|
el.addEventListener("click", toggleEvt);
|
||||||
|
el.addEventListener("keydown", toggleEvt);
|
||||||
|
// Hide.
|
||||||
|
if (hide) {
|
||||||
|
toggleEl(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initThumbnail(el) {
|
||||||
|
// Add event handler.
|
||||||
|
el.addEventListener("mouseenter", showThumbnailEvt);
|
||||||
|
el.addEventListener("mouseleave", hideThumbnail);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initPage(num_hide = null) {
|
||||||
|
const h = document.getElementsByClassName("toggle");
|
||||||
|
let i = 0;
|
||||||
|
for (let el of h) {
|
||||||
|
if (num_hide === null || i < num_hide) {
|
||||||
|
initToggle(el, true);
|
||||||
|
} else {
|
||||||
|
initToggle(el, false);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
const t = document.getElementsByClassName("thumbnail");
|
||||||
|
for (let el of t) initThumbnail(el);
|
||||||
|
}
|
Loading…
Reference in New Issue