2023-08-24 16:04:32 +00:00
|
|
|
var IV = {
|
2023-12-01 14:47:24 +00:00
|
|
|
notify: function(message) {
|
|
|
|
if (window.external && window.external.invoke) {
|
|
|
|
window.external.invoke(JSON.stringify(message));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
frameClickHandler: function(e) {
|
2023-12-04 19:06:44 +00:00
|
|
|
var target = e.target;
|
|
|
|
var context = '';
|
|
|
|
while (target) {
|
2024-03-14 07:22:52 +00:00
|
|
|
if (target.id == 'menu_page_blocker') {
|
|
|
|
IV.notify({ event: 'menu_page_blocker_click' });
|
|
|
|
IV.menuShown(false);
|
|
|
|
return;
|
|
|
|
}
|
2023-12-04 19:06:44 +00:00
|
|
|
if (target.tagName == 'AUDIO' || target.tagName == 'VIDEO') {
|
|
|
|
return;
|
2023-12-01 14:47:24 +00:00
|
|
|
}
|
2023-12-04 19:06:44 +00:00
|
|
|
if (context === ''
|
|
|
|
&& target.hasAttribute
|
|
|
|
&& target.hasAttribute('data-context')) {
|
|
|
|
context = String(target.getAttribute('data-context'));
|
|
|
|
}
|
|
|
|
if (target.tagName == 'A') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
target = target.parentNode;
|
|
|
|
}
|
2024-04-26 15:20:43 +00:00
|
|
|
if (!target || (context === '' && !target.hasAttribute('href'))) {
|
2023-12-04 19:06:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-12-05 07:54:46 +00:00
|
|
|
var base = document.createElement('A');
|
|
|
|
base.href = window.location.href;
|
|
|
|
if (base.origin != target.origin
|
|
|
|
|| base.pathname != target.pathname
|
|
|
|
|| base.search != target.search) {
|
2023-12-04 19:06:44 +00:00
|
|
|
IV.notify({
|
|
|
|
event: 'link_click',
|
|
|
|
url: target.href,
|
|
|
|
context: context,
|
|
|
|
});
|
2023-12-05 07:54:46 +00:00
|
|
|
} else if (target.hash.length < 2) {
|
2023-12-07 10:37:58 +00:00
|
|
|
IV.jumpToHash('');
|
2023-12-05 07:54:46 +00:00
|
|
|
} else {
|
2024-03-24 05:58:50 +00:00
|
|
|
IV.jumpToHash(decodeURIComponent(target.hash.substr(1)));
|
2023-12-07 10:37:58 +00:00
|
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
},
|
2024-03-13 11:08:22 +00:00
|
|
|
getElementTop: function (element) {
|
|
|
|
var top = 0;
|
|
|
|
while (element && !element.classList.contains('page-scroll')) {
|
|
|
|
top += element.offsetTop;
|
|
|
|
element = element.offsetParent;
|
|
|
|
}
|
|
|
|
return top;
|
|
|
|
},
|
2023-12-07 10:37:58 +00:00
|
|
|
jumpToHash: function (hash, instant) {
|
|
|
|
var current = IV.computeCurrentState();
|
|
|
|
current.hash = hash;
|
2024-03-13 08:19:26 +00:00
|
|
|
window.history.replaceState(
|
|
|
|
current,
|
|
|
|
'',
|
|
|
|
'page' + IV.index + '.html');
|
2023-12-07 10:37:58 +00:00
|
|
|
if (hash == '') {
|
|
|
|
IV.scrollTo(0, instant);
|
|
|
|
return;
|
|
|
|
}
|
2023-12-05 07:54:46 +00:00
|
|
|
|
2023-12-07 10:37:58 +00:00
|
|
|
var element = document.getElementsByName(hash)[0];
|
|
|
|
if (element) {
|
2024-03-13 11:08:22 +00:00
|
|
|
IV.scrollTo(IV.getElementTop(element), instant);
|
2023-12-01 14:47:24 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
frameKeyDown: function (e) {
|
2023-12-04 11:48:17 +00:00
|
|
|
const keyW = (e.key === 'w')
|
2023-12-01 14:47:24 +00:00
|
|
|
|| (e.code === 'KeyW')
|
|
|
|
|| (e.keyCode === 87);
|
2023-12-04 11:48:17 +00:00
|
|
|
const keyQ = (e.key === 'q')
|
2023-12-01 14:47:24 +00:00
|
|
|
|| (e.code === 'KeyQ')
|
|
|
|
|| (e.keyCode === 81);
|
2023-12-04 11:48:17 +00:00
|
|
|
const keyM = (e.key === 'm')
|
|
|
|
|| (e.code === 'KeyM')
|
|
|
|
|| (e.keyCode === 77);
|
2023-12-01 14:47:24 +00:00
|
|
|
if ((e.metaKey || e.ctrlKey) && (keyW || keyQ || keyM)) {
|
|
|
|
e.preventDefault();
|
|
|
|
IV.notify({
|
|
|
|
event: 'keydown',
|
|
|
|
modifier: e.ctrlKey ? 'ctrl' : 'cmd',
|
|
|
|
key: keyW ? 'w' : keyQ ? 'q' : 'm',
|
|
|
|
});
|
|
|
|
} else if (e.key === 'Escape' || e.keyCode === 27) {
|
|
|
|
e.preventDefault();
|
2024-02-16 07:25:15 +00:00
|
|
|
if (IV.position) {
|
|
|
|
window.history.back();
|
|
|
|
} else {
|
|
|
|
IV.notify({
|
|
|
|
event: 'keydown',
|
|
|
|
key: 'escape',
|
|
|
|
});
|
|
|
|
}
|
2023-12-01 14:47:24 +00:00
|
|
|
}
|
|
|
|
},
|
2023-12-04 11:48:17 +00:00
|
|
|
frameMouseEnter: function (e) {
|
|
|
|
IV.notify({ event: 'mouseenter' });
|
|
|
|
},
|
|
|
|
frameMouseUp: function (e) {
|
|
|
|
IV.notify({ event: 'mouseup' });
|
|
|
|
},
|
|
|
|
lastScrollTop: 0,
|
|
|
|
frameScrolled: function (e) {
|
2024-02-15 09:48:49 +00:00
|
|
|
const was = IV.lastScrollTop;
|
|
|
|
IV.lastScrollTop = IV.findPageScroll().scrollTop;
|
|
|
|
IV.updateJumpToTop(was < IV.lastScrollTop);
|
2024-03-13 11:08:22 +00:00
|
|
|
IV.checkVideos();
|
2024-02-15 09:48:49 +00:00
|
|
|
},
|
|
|
|
updateJumpToTop: function (scrolledDown) {
|
|
|
|
if (IV.lastScrollTop < 100) {
|
2023-12-04 11:48:17 +00:00
|
|
|
document.getElementById('bottom_up').classList.add('hidden');
|
2024-02-15 09:48:49 +00:00
|
|
|
} else if (scrolledDown && IV.lastScrollTop > 200) {
|
2023-12-04 11:48:17 +00:00
|
|
|
document.getElementById('bottom_up').classList.remove('hidden');
|
|
|
|
}
|
|
|
|
},
|
2023-12-02 18:43:16 +00:00
|
|
|
updateStyles: function (styles) {
|
|
|
|
if (IV.styles !== styles) {
|
|
|
|
IV.styles = styles;
|
|
|
|
document.getElementsByTagName('html')[0].style = styles;
|
2023-12-01 14:47:24 +00:00
|
|
|
}
|
|
|
|
},
|
2023-12-04 19:06:44 +00:00
|
|
|
toggleChannelJoined: function (id, joined) {
|
2024-03-14 07:39:11 +00:00
|
|
|
IV.channelsJoined['channel' + id] = joined;
|
|
|
|
IV.checkChannelButtons();
|
|
|
|
},
|
|
|
|
checkChannelButtons: function() {
|
2023-12-04 19:06:44 +00:00
|
|
|
const channels = document.getElementsByClassName('channel');
|
|
|
|
for (var i = 0; i < channels.length; ++i) {
|
|
|
|
const channel = channels[i];
|
2024-03-14 07:39:11 +00:00
|
|
|
const full = String(channel.getAttribute('data-context'));
|
|
|
|
const value = IV.channelsJoined[full];
|
|
|
|
if (value !== undefined) {
|
|
|
|
channel.classList.toggle('joined', value);
|
2023-12-04 19:06:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2024-02-13 10:55:27 +00:00
|
|
|
slideshowSlide: function(el, delta) {
|
2023-12-01 14:47:24 +00:00
|
|
|
var dir = window.getComputedStyle(el, null).direction || 'ltr';
|
|
|
|
var marginProp = dir == 'rtl' ? 'marginRight' : 'marginLeft';
|
2024-02-13 10:55:27 +00:00
|
|
|
if (delta) {
|
|
|
|
var form = el.parentNode.firstChild;
|
|
|
|
var s = form.s;
|
|
|
|
const next = +s.value + delta;
|
|
|
|
s.value = (next == s.length) ? 0 : (next == -1) ? (s.length - 1) : next;
|
|
|
|
form.nextSibling.firstChild.style[marginProp] = (-100 * s.value) + '%';
|
2023-12-01 14:47:24 +00:00
|
|
|
} else {
|
|
|
|
el.form.nextSibling.firstChild.style[marginProp] = (-100 * el.value) + '%';
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
initPreBlocks: function() {
|
2023-12-04 11:48:17 +00:00
|
|
|
if (!hljs) {
|
|
|
|
return;
|
|
|
|
}
|
2023-12-01 14:47:24 +00:00
|
|
|
var pres = document.getElementsByTagName('pre');
|
|
|
|
for (var i = 0; i < pres.length; i++) {
|
|
|
|
if (pres[i].hasAttribute('data-language')) {
|
|
|
|
hljs.highlightBlock(pres[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
initEmbedBlocks: function() {
|
|
|
|
var iframes = document.getElementsByTagName('iframe');
|
|
|
|
for (var i = 0; i < iframes.length; i++) {
|
|
|
|
(function(iframe) {
|
|
|
|
window.addEventListener('message', function(event) {
|
|
|
|
if (event.source !== iframe.contentWindow ||
|
|
|
|
event.origin != window.origin) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
var data = JSON.parse(event.data);
|
|
|
|
} catch(e) {
|
|
|
|
var data = {};
|
|
|
|
}
|
|
|
|
if (data.eventType == 'resize_frame') {
|
|
|
|
if (data.eventData.height) {
|
|
|
|
iframe.style.height = data.eventData.height + 'px';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, false);
|
|
|
|
})(iframes[i]);
|
|
|
|
}
|
2023-12-04 11:48:17 +00:00
|
|
|
},
|
|
|
|
addRipple: function (button, x, y) {
|
|
|
|
const ripple = document.createElement('span');
|
|
|
|
ripple.classList.add('ripple');
|
|
|
|
|
|
|
|
const inner = document.createElement('span');
|
|
|
|
inner.classList.add('inner');
|
|
|
|
x -= button.offsetLeft;
|
|
|
|
y -= button.offsetTop;
|
|
|
|
|
|
|
|
const mx = button.clientWidth - x;
|
|
|
|
const my = button.clientHeight - y;
|
|
|
|
const sq1 = x * x + y * y;
|
|
|
|
const sq2 = mx * mx + y * y;
|
|
|
|
const sq3 = x * x + my * my;
|
|
|
|
const sq4 = mx * mx + my * my;
|
|
|
|
const radius = Math.sqrt(Math.max(sq1, sq2, sq3, sq4));
|
|
|
|
|
|
|
|
inner.style.width = inner.style.height = `${2 * radius}px`;
|
|
|
|
inner.style.left = `${x - radius}px`;
|
|
|
|
inner.style.top = `${y - radius}px`;
|
|
|
|
inner.classList.add('inner');
|
|
|
|
|
|
|
|
ripple.addEventListener('animationend', function (e) {
|
|
|
|
if (e.animationName === 'fadeOut') {
|
|
|
|
ripple.remove();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
ripple.appendChild(inner);
|
|
|
|
button.appendChild(ripple);
|
|
|
|
},
|
|
|
|
stopRipples: function (button) {
|
2023-12-05 13:25:26 +00:00
|
|
|
const id = button.id ? button.id : button;
|
|
|
|
button = document.getElementById(id);
|
2023-12-04 11:48:17 +00:00
|
|
|
const ripples = button.getElementsByClassName('ripple');
|
|
|
|
for (var i = 0; i < ripples.length; ++i) {
|
|
|
|
const ripple = ripples[i];
|
|
|
|
if (!ripple.classList.contains('hiding')) {
|
|
|
|
ripple.classList.add('hiding');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
init: function () {
|
2024-03-13 08:19:26 +00:00
|
|
|
var current = IV.computeCurrentState();
|
|
|
|
window.history.replaceState(current, '', IV.pageUrl(0));
|
|
|
|
IV.jumpToHash(current.hash, true);
|
2024-02-15 09:48:49 +00:00
|
|
|
|
|
|
|
IV.lastScrollTop = window.history.state.scroll;
|
|
|
|
IV.findPageScroll().onscroll = IV.frameScrolled;
|
2023-12-05 07:54:46 +00:00
|
|
|
|
2023-12-04 11:48:17 +00:00
|
|
|
const buttons = document.getElementsByClassName('fixed_button');
|
|
|
|
for (let i = 0; i < buttons.length; ++i) {
|
|
|
|
const button = buttons[i];
|
|
|
|
button.addEventListener('mousedown', function (e) {
|
|
|
|
IV.addRipple(e.currentTarget, e.clientX, e.clientY);
|
|
|
|
});
|
|
|
|
button.addEventListener('mouseup', function (e) {
|
2023-12-05 13:25:26 +00:00
|
|
|
const id = e.currentTarget.id;
|
|
|
|
setTimeout(function () {
|
|
|
|
IV.stopRipples(id);
|
|
|
|
}, 0);
|
2023-12-04 11:48:17 +00:00
|
|
|
});
|
|
|
|
button.addEventListener('mouseleave', function (e) {
|
|
|
|
IV.stopRipples(e.currentTarget);
|
|
|
|
});
|
|
|
|
}
|
2023-12-07 10:37:58 +00:00
|
|
|
IV.initMedia();
|
|
|
|
IV.notify({ event: 'ready' });
|
2024-02-16 07:25:15 +00:00
|
|
|
|
|
|
|
IV.forceScrollFocus();
|
2024-03-13 11:08:22 +00:00
|
|
|
IV.frameScrolled();
|
2023-12-07 10:37:58 +00:00
|
|
|
},
|
|
|
|
initMedia: function () {
|
2024-03-13 11:08:22 +00:00
|
|
|
var scroll = IV.findPageScroll();
|
|
|
|
const photos = scroll.getElementsByClassName('photo');
|
2024-02-13 07:53:40 +00:00
|
|
|
for (let i = 0; i < photos.length; ++i) {
|
|
|
|
const photo = photos[i];
|
|
|
|
if (photo.classList.contains('loaded')) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const url = photo.style.backgroundImage;
|
|
|
|
if (!url || url.length < 7) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
var img = new Image();
|
|
|
|
img.onload = function () {
|
|
|
|
photo.classList.add('loaded');
|
|
|
|
}
|
|
|
|
img.src = url.substr(5, url.length - 7);
|
|
|
|
if (img.complete) {
|
2024-03-13 11:08:22 +00:00
|
|
|
photo.classList.add('loaded');
|
|
|
|
IV.stopAnimations(photo);
|
2024-02-13 07:53:40 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-13 11:08:22 +00:00
|
|
|
IV.videos = [];
|
|
|
|
const videos = scroll.getElementsByClassName('video');
|
|
|
|
for (let i = 0; i < videos.length; ++i) {
|
|
|
|
const element = videos[i];
|
|
|
|
IV.videos.push({
|
|
|
|
element: element,
|
|
|
|
src: String(element.getAttribute('data-src')),
|
|
|
|
autoplay: (element.getAttribute('data-autoplay') == '1'),
|
|
|
|
loop: (element.getAttribute('data-loop') == '1'),
|
|
|
|
small: (element.getAttribute('data-small') == '1'),
|
|
|
|
filled: (element.firstChild
|
|
|
|
&& element.firstChild.tagName == 'VIDEO'),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
checkVideos: function () {
|
|
|
|
const visibleTop = IV.lastScrollTop;
|
|
|
|
const visibleBottom = visibleTop + IV.findPageScroll().offsetHeight;
|
|
|
|
const videos = IV.videos;
|
2024-02-13 07:53:40 +00:00
|
|
|
for (let i = 0; i < videos.length; ++i) {
|
|
|
|
const video = videos[i];
|
2024-03-13 11:08:22 +00:00
|
|
|
const element = video.element;
|
|
|
|
const wrap = element.offsetParent; // video-wrap
|
|
|
|
const top = IV.getElementTop(wrap);
|
|
|
|
const bottom = top + wrap.offsetHeight;
|
|
|
|
if (top < visibleBottom && bottom > visibleTop) {
|
2024-03-13 14:12:31 +00:00
|
|
|
if (!video.created) {
|
|
|
|
video.created = new Date();
|
|
|
|
video.loaded = false;
|
2024-03-13 11:08:22 +00:00
|
|
|
element.innerHTML = '<video muted class="'
|
|
|
|
+ (video.small ? 'video-small' : '')
|
|
|
|
+ '"'
|
|
|
|
+ (video.autoplay
|
|
|
|
? ' preload="auto" autoplay'
|
|
|
|
: (video.small
|
|
|
|
? ''
|
|
|
|
: ' controls'))
|
|
|
|
+ (video.loop ? ' loop' : '')
|
2024-03-13 14:12:31 +00:00
|
|
|
+ ' oncanplay="IV.checkVideos();"'
|
|
|
|
+ ' onloadeddata="IV.checkVideos();">'
|
|
|
|
+ '<source src="'
|
|
|
|
+ video.src
|
|
|
|
+ '" type="video/mp4" />'
|
2024-03-13 11:08:22 +00:00
|
|
|
+ '</video>';
|
|
|
|
var media = element.firstChild;
|
2024-03-14 08:49:51 +00:00
|
|
|
media.oncontextmenu = function () { return false; };
|
2024-03-13 14:12:31 +00:00
|
|
|
media.oncanplay = IV.checkVideos;
|
|
|
|
media.onloadeddata = IV.checkVideos;
|
|
|
|
}
|
|
|
|
} else if (video.created && video.autoplay) {
|
|
|
|
video.created = false;
|
|
|
|
element.innerHTML = '';
|
|
|
|
}
|
|
|
|
if (video.created && !video.loaded) {
|
|
|
|
var media = element.firstChild;
|
|
|
|
const HAVE_CURRENT_DATA = 2;
|
|
|
|
if (media && media.readyState >= HAVE_CURRENT_DATA) {
|
|
|
|
video.loaded = true;
|
|
|
|
media.classList.add('loaded');
|
|
|
|
if ((new Date() - video.created) < 100) {
|
2024-03-13 11:08:22 +00:00
|
|
|
IV.stopAnimations(media);
|
|
|
|
}
|
|
|
|
}
|
2024-02-13 07:53:40 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-04 19:06:44 +00:00
|
|
|
},
|
|
|
|
showTooltip: function (text) {
|
|
|
|
var toast = document.createElement('div');
|
|
|
|
toast.classList.add('toast');
|
|
|
|
toast.textContent = text;
|
|
|
|
document.body.appendChild(toast);
|
|
|
|
setTimeout(function () {
|
|
|
|
toast.classList.add('hiding');
|
|
|
|
}, 2000);
|
|
|
|
setTimeout(function () {
|
|
|
|
document.body.removeChild(toast);
|
|
|
|
}, 3000);
|
2023-12-04 11:48:17 +00:00
|
|
|
},
|
2023-12-07 10:37:58 +00:00
|
|
|
scrollTo: function (y, instant) {
|
2024-02-15 09:48:49 +00:00
|
|
|
if (y < 200) {
|
|
|
|
document.getElementById('bottom_up').classList.add('hidden');
|
|
|
|
}
|
2023-12-07 10:37:58 +00:00
|
|
|
IV.findPageScroll().scrollTo({
|
|
|
|
top: y || 0,
|
|
|
|
behavior: instant ? 'instant' : 'smooth'
|
|
|
|
});
|
2023-12-05 13:25:26 +00:00
|
|
|
},
|
2023-12-07 10:37:58 +00:00
|
|
|
computeCurrentState: function () {
|
|
|
|
var now = IV.findPageScroll();
|
|
|
|
return {
|
|
|
|
position: IV.position,
|
|
|
|
index: IV.index,
|
|
|
|
hash: ((!window.history.state
|
|
|
|
|| window.history.state.hash === undefined)
|
|
|
|
? window.location.hash.substr(1)
|
|
|
|
: window.history.state.hash),
|
|
|
|
scroll: now ? now.scrollTop : 0
|
|
|
|
};
|
|
|
|
},
|
2024-03-13 08:19:26 +00:00
|
|
|
pageUrl: function (index, hash) {
|
|
|
|
var result = 'page' + index + '.html';
|
|
|
|
if (hash) {
|
|
|
|
result += '#' + hash;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
},
|
2023-12-07 10:37:58 +00:00
|
|
|
navigateTo: function (index, hash) {
|
|
|
|
if (!index && !IV.index) {
|
|
|
|
IV.navigateToDOM(IV.index, hash);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
IV.pending = [index, hash];
|
|
|
|
if (!IV.cache[index]) {
|
2024-03-11 12:59:11 +00:00
|
|
|
IV.loadPage(index);
|
2023-12-07 10:37:58 +00:00
|
|
|
} else if (IV.cache[index].dom) {
|
|
|
|
IV.navigateToDOM(index, hash);
|
|
|
|
} else if (IV.cache[index].content) {
|
|
|
|
IV.navigateToLoaded(index, hash);
|
|
|
|
}
|
|
|
|
},
|
2024-03-11 12:59:11 +00:00
|
|
|
applyUpdatedContent: function (index) {
|
|
|
|
if (IV.index != index) {
|
|
|
|
IV.cache[index].contentUpdated = (IV.cache[index].dom !== undefined);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var data = JSON.parse(IV.cache[index].content);
|
|
|
|
var article = function (el) {
|
|
|
|
return el.getElementsByTagName('article')[0];
|
|
|
|
};
|
2024-04-26 15:20:43 +00:00
|
|
|
var footer = function (el) {
|
|
|
|
return el.getElementsByClassName('page-footer')[0];
|
|
|
|
};
|
|
|
|
var from = IV.findPageScroll();
|
|
|
|
var to = IV.makeScrolledContent(data.html);
|
|
|
|
morphdom(article(from), article(to), {
|
2024-03-11 12:59:11 +00:00
|
|
|
onBeforeElUpdated: function (fromEl, toEl) {
|
2024-03-13 11:08:22 +00:00
|
|
|
if (fromEl.classList.contains('video')
|
|
|
|
&& toEl.classList.contains('video')
|
|
|
|
&& fromEl.hasAttribute('data-src')
|
|
|
|
&& toEl.hasAttribute('data-src')
|
|
|
|
&& (fromEl.getAttribute('data-src')
|
|
|
|
== toEl.getAttribute('data-src'))) {
|
|
|
|
return false;
|
2024-03-14 07:39:11 +00:00
|
|
|
} else if (fromEl.tagName == 'SECTION'
|
|
|
|
&& fromEl.classList.contains('channel')
|
|
|
|
&& fromEl.hasAttribute('data-context')
|
|
|
|
&& toEl.tagName == 'SECTION'
|
|
|
|
&& toEl.classList.contains('channel')
|
|
|
|
&& toEl.hasAttribute('data-context')
|
|
|
|
&& (String(fromEl.getAttribute('data-context'))
|
|
|
|
== String(toEl.getAttribute('data-context')))) {
|
|
|
|
return false;
|
2024-03-13 11:08:22 +00:00
|
|
|
} else if (fromEl.classList.contains('loaded')) {
|
2024-03-11 12:59:11 +00:00
|
|
|
toEl.classList.add('loaded');
|
|
|
|
}
|
|
|
|
return !fromEl.isEqualNode(toEl);
|
|
|
|
}
|
|
|
|
});
|
2024-04-26 15:20:43 +00:00
|
|
|
morphdom(footer(from), footer(to));
|
2024-03-11 12:59:11 +00:00
|
|
|
IV.initMedia();
|
|
|
|
eval(data.js);
|
|
|
|
},
|
|
|
|
loadPage: function (index) {
|
|
|
|
if (!IV.cache[index]) {
|
|
|
|
IV.cache[index] = {};
|
|
|
|
}
|
|
|
|
IV.cache[index].loading = true;
|
2023-12-07 10:37:58 +00:00
|
|
|
|
2024-03-11 12:59:11 +00:00
|
|
|
let xhr = new XMLHttpRequest();
|
|
|
|
xhr.onload = function () {
|
|
|
|
IV.cache[index].loading = false;
|
|
|
|
IV.cache[index].content = xhr.responseText;
|
|
|
|
IV.applyUpdatedContent(index);
|
|
|
|
if (IV.pending && IV.pending[0] == index) {
|
|
|
|
IV.navigateToLoaded(index, IV.pending[1]);
|
|
|
|
}
|
|
|
|
if (IV.cache[index].reloadPending) {
|
|
|
|
IV.cache[index].reloadPending = false;
|
|
|
|
IV.reloadPage(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
xhr.open('GET', 'page' + index + '.json');
|
|
|
|
xhr.send();
|
|
|
|
},
|
|
|
|
reloadPage: function (index) {
|
|
|
|
if (IV.cache[index] && IV.cache[index].loading) {
|
|
|
|
IV.cache[index].reloadPending = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
IV.loadPage(index);
|
|
|
|
},
|
|
|
|
|
|
|
|
makeScrolledContent: function (html) {
|
|
|
|
var result = document.createElement('div');
|
|
|
|
result.className = 'page-scroll';
|
|
|
|
result.tabIndex = '-1';
|
2024-04-26 15:20:43 +00:00
|
|
|
result.innerHTML = html.trim();
|
2024-03-11 12:59:11 +00:00
|
|
|
result.onscroll = IV.frameScrolled;
|
|
|
|
return result;
|
|
|
|
},
|
2023-12-07 10:37:58 +00:00
|
|
|
navigateToLoaded: function (index, hash) {
|
|
|
|
if (IV.cache[index].dom) {
|
|
|
|
IV.navigateToDOM(index, hash);
|
|
|
|
} else {
|
|
|
|
var data = JSON.parse(IV.cache[index].content);
|
2024-03-11 12:59:11 +00:00
|
|
|
IV.cache[index].dom = IV.makeScrolledContent(data.html);
|
2023-12-07 10:37:58 +00:00
|
|
|
|
|
|
|
IV.navigateToDOM(index, hash);
|
|
|
|
eval(data.js);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
navigateToDOM: function (index, hash) {
|
|
|
|
IV.pending = null;
|
|
|
|
if (IV.index == index) {
|
2024-03-13 08:19:26 +00:00
|
|
|
IV.jumpToHash(hash);
|
2024-02-16 07:25:15 +00:00
|
|
|
IV.forceScrollFocus();
|
2023-12-07 10:37:58 +00:00
|
|
|
return;
|
|
|
|
}
|
2024-03-13 08:19:26 +00:00
|
|
|
window.history.replaceState(
|
|
|
|
IV.computeCurrentState(),
|
|
|
|
'',
|
|
|
|
IV.pageUrl(IV.index));
|
2023-12-07 10:37:58 +00:00
|
|
|
|
|
|
|
IV.position = IV.position + 1;
|
|
|
|
window.history.pushState(
|
|
|
|
{ position: IV.position, index: index, hash: hash },
|
|
|
|
'',
|
2024-03-13 08:19:26 +00:00
|
|
|
IV.pageUrl(index));
|
2023-12-07 10:37:58 +00:00
|
|
|
IV.showDOM(index, hash);
|
|
|
|
},
|
|
|
|
findPageScroll: function () {
|
|
|
|
var all = document.getElementsByClassName('page-scroll');
|
|
|
|
for (i = 0; i < all.length; ++i) {
|
|
|
|
if (!all[i].classList.contains('hidden-left')
|
|
|
|
&& !all[i].classList.contains('hidden-right')) {
|
|
|
|
return all[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
showDOM: function (index, hash, scroll) {
|
|
|
|
IV.pending = null;
|
|
|
|
if (IV.index != index) {
|
|
|
|
var initial = !window.history.state
|
|
|
|
|| window.history.state.position === undefined;
|
|
|
|
var back = initial
|
|
|
|
|| IV.position > window.history.state.position;
|
|
|
|
IV.position = initial ? 0 : window.history.state.position;
|
|
|
|
|
|
|
|
var now = IV.cache[index].dom;
|
|
|
|
var was = IV.findPageScroll();
|
|
|
|
if (!IV.cache[IV.index]) {
|
|
|
|
IV.cache[IV.index] = {};
|
|
|
|
}
|
|
|
|
IV.cache[IV.index].dom = was;
|
|
|
|
was.parentNode.appendChild(now);
|
|
|
|
if (scroll !== undefined) {
|
|
|
|
now.scrollTop = scroll;
|
2024-03-11 12:59:11 +00:00
|
|
|
setTimeout(function () {
|
|
|
|
// When returning by history.back to an URL with a hash
|
|
|
|
// for the first time browser forces the scroll to the
|
|
|
|
// hash instead of the saved scroll position.
|
|
|
|
//
|
|
|
|
// This workaround prevents incorrect scroll position.
|
|
|
|
now.scrollTop = scroll;
|
|
|
|
}, 0);
|
2023-12-07 10:37:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
now.classList.add(back ? 'hidden-left' : 'hidden-right');
|
|
|
|
now.classList.remove(back ? 'hidden-right' : 'hidden-left');
|
2024-03-13 11:08:22 +00:00
|
|
|
IV.stopAnimations(now.firstChild);
|
2023-12-07 10:37:58 +00:00
|
|
|
|
|
|
|
if (!was.listening) {
|
|
|
|
was.listening = true;
|
|
|
|
was.firstChild.addEventListener('transitionend', function (e) {
|
|
|
|
if (was.classList.contains('hidden-left')
|
|
|
|
|| was.classList.contains('hidden-right')) {
|
|
|
|
if (was.parentNode) {
|
|
|
|
was.parentNode.removeChild(was);
|
2024-03-13 11:08:22 +00:00
|
|
|
var videos = was.getElementsByClassName('video');
|
|
|
|
for (var i = 0; i < videos.length; ++i) {
|
|
|
|
videos[i].innerHTML = '';
|
|
|
|
}
|
2023-12-07 10:37:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
was.classList.add(back ? 'hidden-right' : 'hidden-left');
|
|
|
|
now.classList.remove(back ? 'hidden-left' : 'hidden-right');
|
|
|
|
|
|
|
|
IV.index = index;
|
2024-03-12 09:00:51 +00:00
|
|
|
IV.notify({
|
|
|
|
event: 'location_change',
|
|
|
|
index: IV.index,
|
|
|
|
position: IV.position,
|
|
|
|
hash: IV.computeCurrentState().hash,
|
|
|
|
});
|
2024-03-11 12:59:11 +00:00
|
|
|
if (IV.cache[index].contentUpdated) {
|
|
|
|
IV.cache[index].contentUpdated = false;
|
|
|
|
IV.applyUpdatedContent(index);
|
|
|
|
} else {
|
|
|
|
IV.initMedia();
|
|
|
|
}
|
2024-03-14 07:39:11 +00:00
|
|
|
IV.checkChannelButtons();
|
2023-12-07 10:37:58 +00:00
|
|
|
if (scroll === undefined) {
|
|
|
|
IV.jumpToHash(hash, true);
|
2024-02-15 09:48:49 +00:00
|
|
|
} else {
|
|
|
|
IV.lastScrollTop = scroll;
|
|
|
|
IV.updateJumpToTop(true);
|
2023-12-07 10:37:58 +00:00
|
|
|
}
|
|
|
|
} else if (scroll !== undefined) {
|
2024-03-13 08:19:26 +00:00
|
|
|
IV.scrollTo(scroll);
|
2024-02-15 09:48:49 +00:00
|
|
|
IV.lastScrollTop = scroll;
|
|
|
|
IV.updateJumpToTop(true);
|
2023-12-07 10:37:58 +00:00
|
|
|
} else {
|
2024-03-13 08:19:26 +00:00
|
|
|
IV.jumpToHash(hash);
|
2023-12-07 10:37:58 +00:00
|
|
|
}
|
2024-02-16 07:25:15 +00:00
|
|
|
|
|
|
|
IV.forceScrollFocus();
|
2024-03-13 11:08:22 +00:00
|
|
|
IV.frameScrolled();
|
2024-02-16 07:25:15 +00:00
|
|
|
},
|
|
|
|
forceScrollFocus: function () {
|
|
|
|
IV.findPageScroll().focus();
|
|
|
|
setTimeout(function () {
|
|
|
|
// Doesn't work on #hash-ed pages in Windows WebView2 otherwise.
|
|
|
|
IV.findPageScroll().focus();
|
|
|
|
}, 100);
|
2023-12-07 10:37:58 +00:00
|
|
|
},
|
2024-03-13 11:08:22 +00:00
|
|
|
stopAnimations: function (element) {
|
|
|
|
element.getAnimations().forEach(
|
|
|
|
(animation) => animation.finish());
|
|
|
|
},
|
2023-12-07 10:37:58 +00:00
|
|
|
back: function () {
|
|
|
|
window.history.back();
|
|
|
|
},
|
2024-03-14 07:22:52 +00:00
|
|
|
menuShown: function (shown) {
|
|
|
|
var already = document.getElementById('menu_page_blocker');
|
|
|
|
if (already && shown) {
|
|
|
|
return;
|
|
|
|
} else if (already) {
|
|
|
|
document.body.removeChild(already);
|
|
|
|
return;
|
|
|
|
} else if (!shown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var blocker = document.createElement('div');
|
|
|
|
blocker.id = 'menu_page_blocker';
|
|
|
|
document.body.appendChild(blocker);
|
|
|
|
},
|
2023-12-07 10:37:58 +00:00
|
|
|
|
2024-03-13 11:08:22 +00:00
|
|
|
videos: {},
|
|
|
|
videosPlaying: {},
|
|
|
|
|
2023-12-07 10:37:58 +00:00
|
|
|
cache: {},
|
2024-03-14 07:39:11 +00:00
|
|
|
channelsJoined: {},
|
2023-12-07 10:37:58 +00:00
|
|
|
index: 0,
|
|
|
|
position: 0
|
2023-08-24 16:04:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
document.onclick = IV.frameClickHandler;
|
2023-12-01 14:47:24 +00:00
|
|
|
document.onkeydown = IV.frameKeyDown;
|
2023-12-04 11:48:17 +00:00
|
|
|
document.onmouseenter = IV.frameMouseEnter;
|
|
|
|
document.onmouseup = IV.frameMouseUp;
|
2024-03-13 11:08:22 +00:00
|
|
|
document.onresize = IV.checkVideos;
|
2023-08-24 16:04:32 +00:00
|
|
|
window.onmessage = IV.postMessageHandler;
|
2023-12-07 10:37:58 +00:00
|
|
|
window.addEventListener('popstate', function (e) {
|
|
|
|
if (e.state) {
|
|
|
|
IV.showDOM(e.state.index, e.state.hash, e.state.scroll);
|
|
|
|
}
|
|
|
|
});
|
2024-02-16 07:25:15 +00:00
|
|
|
document.addEventListener("DOMContentLoaded", IV.forceScrollFocus);
|