#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pscript import RawJS
from flexx import flx
from ipfsdocs.placeholder import PlaceHolder
from ipfsdocs.common import (
URL,
positivemod,
set_to_localstorage, get_from_localstorage,
)
from ipfsdocs.log import info
class Slide(flx.Layout):
index = flx.IntProp(0, settable=True)
thumbnail_width = flx.IntProp(1024, settable=True)
CSS = """
.slide_placeholder {
margin: auto;
}
.flx-Slide {
overflow-x: scroll;
}
/* from https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_hide_scrollbar_keep_func */
.flx-Slide::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.flx-Slide {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
"""
def _create_dom(self):
return [
flx.create_element("div"),
]
def _render_dom(self):
return [
flx.create_element(
"table", {},
flx.create_element(
"tr", {},
[
flx.create_element(
"td", {},
child.outernode
)
for child in self.children
]
)
),
]
@flx.reaction("index")
def save_index(self):
set_to_localstorage("slide_index", {"slide_index": self.index})
@flx.reaction("index")
def pause_video(self, *events):
event = events[-1]
if event.old_value != event.new_value and event.old_value is not None:
self.placeholders[event.old_value].pause_video()
def is_visible(self):
return any([placeholder.visible for placeholder in self.placeholders])
@flx.reaction(
"root.state.autoplay",
"placeholders*.visible",
"placeholders*.stopped_video",
"placeholders*.ended_video",
"placeholders*.playing_video",
"root.jssays.contextmenu",
"root.jssays.contextmenu_exit",
"root.jssays.pinching_placeholder",
"root.jssays.pinched_placeholder",
"root.frontend.inmodal",
)
def update_autoplay(self, *events):
event = events[-1]
if (
self.root.state.autoplay
and not event.type == "playing_video"
and not event.type == "contextmenu"
and not event.type == "pinching_placeholder"
and not self.root.frontend.inmodal
and self.is_visible()
):
self.start_autoplay_timer()
else:
self.stop_autoplay_timer()
def start_autoplay_timer(self):
global window
if self.autoplay_interval is not None:
window.clearInterval(self.autoplay_interval)
self.autoplay_interval = window.setInterval(self.next, 60000)
def stop_autoplay_timer(self):
global window
window.clearInterval(self.autoplay_interval)
self.autoplay_interval = None
@flx.reaction("key_down")
def on_key_down(self, *events):
if self.root.frontend.inmodal:
return
for event in events:
if event.key == "ArrowRight":
self.next()
elif event.key == "ArrowLeft":
self.previous()
elif event.key == " ":
self.placeholders[self.index].toggle_selection()
elif event.key == "d":
self.placeholders[self.index].ask_delete()
elif event.key == "t":
self.placeholders[self.index].toggle_video()
def page_next(self):
self.set_index(0)
self.root.state.next_page()
def page_previous(self):
self.set_index(self.root.state.number_per_page - 1)
self.root.state.previous_page()
def next(self):
index = self.index + 1
if (
self.root.state.in_last_page
and
index >= self.root.state.number_of_elements_on_this_page
):
self.goto_first()
elif index >= self.root.state.number_per_page:
self.page_next()
else:
self.set_index(index)
def previous(self):
index = self.index - 1
if (
self.root.state.in_first_page
and
index < 0
):
self.goto_last()
elif index < 0:
self.page_previous()
else:
self.set_index(index)
def goto_last(self):
index = positivemod(
self.root.state.number_of_elements - 1,
self.root.state.number_per_page
)
self.set_index(index)
self.root.state.goto_last_page()
def goto_first(self):
self.set_index(0)
self.root.state.goto_first_page()
@flx.reaction("index", "placeholders*.size")
def scroll_to_current_index(self, *ev):
# the scroll may be impacted by the index change or the window resizing
self.scroll_to_placeholder(
self.placeholders[self.index]
)
@flx.reaction("index")
def adjust_load(self):
for i, placeholder in enumerate(self.placeholders):
placeholder.set_load(
self.index - 2 <= i <= self.index + 2
)
def scroll_to_placeholder(self, placeholder):
node = placeholder.node
RawJS("$")(self.outernode).animate(
{
"scrollLeft": node.offsetLeft,
},
100,
"swing",
)
@flx.reaction("size")
def tell_size(self):
for placeholder in self.placeholders:
placeholder.apply_style(f"height: {self.size[1]}px; width: {self.size[0]}px; ")
self.scroll_to_current_index()
@flx.reaction("root.state.focused_cid")
def update_index_on_focus(self, *events):
for index, placeholder in enumerate(self.placeholders):
if placeholder.cid == self.root.state.focused_cid:
self.set_index(index)
@flx.reaction("root.state.query_results", "root.state.page", "root.state.number_per_page")
def new_query_results(self, *events):
global undefined, moment
for i, placeholder in enumerate(self.placeholders):
row = self.root.state.query_results[i + (self.root.state.page * self.root.state.number_per_page)]
placeholder.show()
if row == undefined:
placeholder.set_html("Nothing else")
else:
placeholder.set_url(f'{row["cid"]}?filename={row["filename"]}')
placeholder.set_cid(row["cid"])
placeholder.set_webcid(row["web_cid"])
placeholder.set_filename(row["filename"])
placeholder.set_mimetype(row["mimetype"])
placeholder.update_tags(row["tags"])
title = f"{moment(row['date']).format('LLLL')}: {row['description']}"
placeholder.set_description(title)
if row["class"] == "photo":
placeholder.set_html(
f''
f' '
)
elif row["class"] == "video":
placeholder.set_html(
f''
f' '
)
else:
placeholder.set_html(f"euh: {row['class']}")
def init(self):
self.placeholders = []
self.setup_placeholders()
self.node.onscroll = self.onscroll
self.idle_timer = None
self.autoplay_interval = None
self.set_index(
get_from_localstorage("slide_index")["slide_index"] or 0
)
def on_swipeleft(self):
if self.root.frontend.inmodal:
return
self.next()
def on_swiperight(self):
if self.root.frontend.inmodal:
return
self.previous()
def intersect_debug(self, entries):
for entry in entries:
entry.target.flx_parent.set_visible(entry.isIntersecting)
entry.target.flx_parent.set_intersection_ratio(
entry.intersectionRatio
)
@flx.reaction("root.state.number_per_page")
def setup_placeholders(self):
global Hammer
global IntersectionObserver
self.observer = IntersectionObserver(
self.intersect_debug,
{
"root": self.node,
"threshold": 0.5,
"rootMargin": "100%",
},
)
for placeholder in self.placeholders:
placeholder.dispose()
with self:
self.placeholders = [
PlaceHolder(custom_css_class="slide_placeholder")
for i in range(self.root.state.number_per_page)
]
for placeholder in self.placeholders:
self.observer.observe(placeholder.node)
placeholder.hammer.on("swipeleft", lambda: self.on_swipeleft())
placeholder.hammer.on("swiperight", lambda: self.on_swiperight())