Merge pull request #56 from ZiRo-/master
Add inline webm playback & make js files modular
This commit is contained in:
commit
a423b6bfe6
21
build-js.sh
Executable file
21
build-js.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
root=$(readlink -e $(dirname $0))
|
||||
|
||||
cd $root
|
||||
if [ -z "$GOPATH" ]; then
|
||||
export GOPATH=$PWD/go
|
||||
mkdir -p $GOPATH
|
||||
fi
|
||||
|
||||
if [ ! -f $GOPATH/bin/minify ]; then
|
||||
go get github.com/tdewolff/minify/cmd/minify
|
||||
fi
|
||||
|
||||
echo -e "//For source code and license information please check https://github.com/majestrate/nntpchan \n" > ./contrib/static/nntpchan.js
|
||||
|
||||
|
||||
cat ./contrib/js/main.js_ | $GOPATH/bin/minify --mime=text/javascript >> ./contrib/static/nntpchan.js
|
||||
for f in ./contrib/js/*.js ; do
|
||||
cat $f | $GOPATH/bin/minify --mime=text/javascript >> ./contrib/static/nntpchan.js
|
||||
done
|
41
contrib/js/api.js
Normal file
41
contrib/js/api.js
Normal file
@ -0,0 +1,41 @@
|
||||
// call an api method
|
||||
// handler(json_object) on success
|
||||
// handler(null) on fail
|
||||
function nntpchan_apicall(url, handler, err_handler) {
|
||||
var ajax = new XMLHttpRequest();
|
||||
ajax.onreadystatechange = function() {
|
||||
if (ajax.readyState == XMLHttpRequest.DONE ) {
|
||||
var status = ajax.status;
|
||||
var j = null;
|
||||
if (status == 200) {
|
||||
// found
|
||||
try {
|
||||
j = JSON.parse(ajax.responseText);
|
||||
} catch (e) {} // ignore parse error
|
||||
} else if (status == 410) {
|
||||
if (err_handler) {err_handler("cannot fetch post: api disabled");}
|
||||
return;
|
||||
}
|
||||
handler(j);
|
||||
}
|
||||
};
|
||||
ajax.open("GET", url);
|
||||
ajax.send();
|
||||
}
|
||||
|
||||
// build post from json
|
||||
// inject into parent
|
||||
// if j is null then inject "not found" post
|
||||
function nntpchan_buildpost(parent, j) {
|
||||
var post = document.createElement("div");
|
||||
if (j) {
|
||||
// huehuehue
|
||||
post.innerHTML = j.PostMarkup;
|
||||
inject_hover_for_element(post);
|
||||
} else {
|
||||
post.setAttribute("class", "notfound post");
|
||||
post.appendChild(document.createTextNode("post not found"));
|
||||
}
|
||||
parent.appendChild(post);
|
||||
}
|
||||
|
78
contrib/js/backlink.js
Normal file
78
contrib/js/backlink.js
Normal file
@ -0,0 +1,78 @@
|
||||
// insert a backlink for a post given its short hash
|
||||
function nntpchan_backlink(shorthash) {
|
||||
var elem = document.getElementById("postform_message");
|
||||
if ( elem )
|
||||
{
|
||||
elem.value += ">>" + shorthash.substr(0,10) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// inject post hover behavior
|
||||
function inject_hover(prefix, el, parent) {
|
||||
if (!prefix) { throw "prefix is not defined"; }
|
||||
var linkhash = el.getAttribute("backlinkhash");
|
||||
if (!linkhash) { throw "linkhash undefined"; }
|
||||
console.log("rewrite linkhash "+linkhash);
|
||||
|
||||
var elem = document.createElement("span");
|
||||
elem.setAttribute("class", "backlink_rewritten");
|
||||
elem.appendChild(document.createTextNode(">>"+linkhash.substr(0,10)));
|
||||
if (!parent) {
|
||||
parent = el.parentNode;
|
||||
}
|
||||
parent.removeChild(el);
|
||||
parent.appendChild(elem);
|
||||
|
||||
elem.onclick = function(ev) {
|
||||
if(parent.backlink) {
|
||||
nntpchan_apicall(prefix+"api/find?hash="+linkhash, function(j) {
|
||||
var wrapper = document.createElement("div");
|
||||
wrapper.setAttribute("class", "hover "+linkhash);
|
||||
if (j == null) {
|
||||
// not found?
|
||||
wrapper.setAttribute("class", "hover notfound-hover "+linkhash);
|
||||
wrapper.appendChild(document.createTextNode("not found"));
|
||||
} else {
|
||||
// wrap backlink
|
||||
nntpchan_buildpost(wrapper, j);
|
||||
}
|
||||
parent.appendChild(wrapper);
|
||||
parent.backlink = false;
|
||||
}, function(msg) {
|
||||
var wrapper = document.createElement("div");
|
||||
wrapper.setAttribute("class", "hover "+linkhash);
|
||||
wrapper.appendChild(document.createTextNode(msg));
|
||||
parent.appendChild(wrapper);
|
||||
parent.backlink = false;
|
||||
});
|
||||
} else {
|
||||
var elems = document.getElementsByClassName(linkhash);
|
||||
if (!elems) throw "bad state, no backlinks open?";
|
||||
for (var idx = 0 ; idx < elems.length; idx ++ ) {
|
||||
elems[idx].parentNode.removeChild(elems[idx]);
|
||||
}
|
||||
parent.backlink = true;
|
||||
}
|
||||
};
|
||||
parent.backlink = true;
|
||||
}
|
||||
|
||||
// inject post hover for all backlinks in an element
|
||||
function inject_hover_for_element(elem) {
|
||||
var elems = elem.getElementsByClassName("backlink");
|
||||
var ls = [];
|
||||
var l = elems.length;
|
||||
for ( var idx = 0 ; idx < l ; idx ++ ) {
|
||||
var e = elems[idx];
|
||||
ls.push(e);
|
||||
}
|
||||
for( var elem in ls ) {
|
||||
inject_hover(prefix, ls[elem]);
|
||||
}
|
||||
}
|
||||
|
||||
function init(prefix) {
|
||||
// inject posthover ...
|
||||
inject_hover_for_element(document);
|
||||
}
|
||||
|
13
contrib/js/banner.js
Normal file
13
contrib/js/banner.js
Normal file
@ -0,0 +1,13 @@
|
||||
var banner_count = 3;
|
||||
|
||||
// inject a banner into an element
|
||||
function nntpchan_inject_banners(elem, prefix) {
|
||||
var n = Math.floor(Math.random() * banner_count);
|
||||
var banner = prefix + "static/banner_"+n+".jpg";
|
||||
var e = document.createElement("img");
|
||||
e.src = banner;
|
||||
e.id = "nntpchan_banner";
|
||||
elem.appendChild(e);
|
||||
}
|
||||
|
||||
|
246
contrib/js/expand-video.js
Normal file
246
contrib/js/expand-video.js
Normal file
@ -0,0 +1,246 @@
|
||||
/* This file is dedicated to the public domain; you may do as you wish with it. */
|
||||
/* Note: This code expects the global variable configRoot to be set. */
|
||||
var configRoot = "";
|
||||
|
||||
|
||||
if (typeof _ == 'undefined') {
|
||||
var _ = function(a) { return a; };
|
||||
}
|
||||
|
||||
function setupVideo(thumb, url) {
|
||||
if (thumb.videoAlreadySetUp) return;
|
||||
thumb.videoAlreadySetUp = true;
|
||||
|
||||
var video = null;
|
||||
var videoContainer, videoHide;
|
||||
var expanded = false;
|
||||
var hovering = false;
|
||||
//var loop = setting("videoloop");
|
||||
var loop = true;
|
||||
var loopControls = [document.createElement("span"), document.createElement("span")];
|
||||
var fileInfo = thumb.parentNode.querySelector(".fileinfo");
|
||||
var mouseDown = false;
|
||||
|
||||
function unexpand() {
|
||||
if (expanded) {
|
||||
expanded = false;
|
||||
if (video.pause) video.pause();
|
||||
videoContainer.style.display = "none";
|
||||
thumb.style.display = "inline";
|
||||
video.style.maxWidth = "inherit";
|
||||
video.style.maxHeight = "inherit";
|
||||
}
|
||||
}
|
||||
|
||||
function unhover() {
|
||||
if (hovering) {
|
||||
hovering = false;
|
||||
if (video.pause) video.pause();
|
||||
videoContainer.style.display = "none";
|
||||
video.style.maxWidth = "inherit";
|
||||
video.style.maxHeight = "inherit";
|
||||
}
|
||||
}
|
||||
|
||||
// Create video element if does not exist yet
|
||||
function getVideo() {
|
||||
if (video == null) {
|
||||
video = document.createElement("video");
|
||||
video.src = url;
|
||||
video.loop = loop;
|
||||
video.innerText = _("Your browser does not support HTML5 video.");
|
||||
|
||||
videoHide = document.createElement("img");
|
||||
videoHide.src = configRoot + "static/collapse.gif";
|
||||
videoHide.alt = "[ - ]";
|
||||
videoHide.title = "Collapse video";
|
||||
videoHide.style.marginLeft = "-15px";
|
||||
videoHide.style.cssFloat = "left";
|
||||
videoHide.addEventListener("click", unexpand, false);
|
||||
|
||||
videoContainer = document.createElement("div");
|
||||
videoContainer.style.paddingLeft = "15px";
|
||||
videoContainer.style.display = "none";
|
||||
videoContainer.appendChild(videoHide);
|
||||
videoContainer.appendChild(video);
|
||||
thumb.parentNode.insertBefore(videoContainer, thumb.nextSibling);
|
||||
|
||||
// Dragging to the left collapses the video
|
||||
video.addEventListener("mousedown", function(e) {
|
||||
if (e.button == 0) mouseDown = true;
|
||||
}, false);
|
||||
video.addEventListener("mouseup", function(e) {
|
||||
if (e.button == 0) mouseDown = false;
|
||||
}, false);
|
||||
video.addEventListener("mouseenter", function(e) {
|
||||
mouseDown = false;
|
||||
}, false);
|
||||
video.addEventListener("mouseout", function(e) {
|
||||
if (mouseDown && e.clientX - video.getBoundingClientRect().left <= 0) {
|
||||
unexpand();
|
||||
}
|
||||
mouseDown = false;
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Clicking on thumbnail expands video
|
||||
thumb.addEventListener("click", function(e) {
|
||||
if (!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
||||
getVideo();
|
||||
expanded = true;
|
||||
hovering = false;
|
||||
|
||||
video.style.position = "static";
|
||||
video.style.pointerEvents = "inherit";
|
||||
video.style.display = "inline";
|
||||
videoHide.style.display = "inline";
|
||||
videoContainer.style.display = "block";
|
||||
videoContainer.style.position = "static";
|
||||
video.parentNode.parentNode.removeAttribute('style');
|
||||
thumb.style.display = "none";
|
||||
|
||||
//video.muted = (setting("videovolume") == 0);
|
||||
//video.volume = setting("videovolume");
|
||||
video.controls = true;
|
||||
if (video.readyState == 0) {
|
||||
video.addEventListener("loadedmetadata", expand2, false);
|
||||
} else {
|
||||
setTimeout(expand2, 0);
|
||||
}
|
||||
video.play();
|
||||
e.preventDefault();
|
||||
}
|
||||
}, false);
|
||||
|
||||
function expand2() {
|
||||
video.style.maxWidth = "100%";
|
||||
video.style.maxHeight = window.innerHeight + "px";
|
||||
var bottom = video.getBoundingClientRect().bottom;
|
||||
if (bottom > window.innerHeight) {
|
||||
window.scrollBy(0, bottom - window.innerHeight);
|
||||
}
|
||||
// work around Firefox volume control bug
|
||||
//video.volume = Math.max(setting("videovolume") - 0.001, 0);
|
||||
//video.volume = setting("videovolume");
|
||||
}
|
||||
|
||||
// Hovering over thumbnail displays video
|
||||
thumb.addEventListener("mouseover", function(e) {
|
||||
//if (setting("videohover")) {
|
||||
if (false) { // DOESN'T WORK YET
|
||||
getVideo();
|
||||
expanded = false;
|
||||
hovering = true;
|
||||
|
||||
var docRight = document.documentElement.getBoundingClientRect().right;
|
||||
var thumbRight = thumb.querySelector("img, video").getBoundingClientRect().right;
|
||||
var maxWidth = docRight - thumbRight - 20;
|
||||
if (maxWidth < 250) maxWidth = 250;
|
||||
|
||||
video.style.position = "fixed";
|
||||
video.style.right = "0px";
|
||||
video.style.top = "0px";
|
||||
var docRight = document.documentElement.getBoundingClientRect().right;
|
||||
var thumbRight = thumb.querySelector("img, video").getBoundingClientRect().right;
|
||||
video.style.maxWidth = maxWidth + "px";
|
||||
video.style.maxHeight = "100%";
|
||||
video.style.pointerEvents = "none";
|
||||
|
||||
video.style.display = "inline";
|
||||
videoHide.style.display = "none";
|
||||
videoContainer.style.display = "inline";
|
||||
videoContainer.style.position = "fixed";
|
||||
|
||||
//video.muted = (setting("videovolume") == 0);
|
||||
//video.volume = setting("videovolume");
|
||||
video.controls = false;
|
||||
video.play();
|
||||
}
|
||||
}, false);
|
||||
|
||||
thumb.addEventListener("mouseout", unhover, false);
|
||||
|
||||
// Scroll wheel on thumbnail adjusts default volume
|
||||
thumb.addEventListener("wheel", function(e) {
|
||||
//if (setting("videohover")) {
|
||||
if (true) {
|
||||
//var volume = setting("videovolume");
|
||||
if (e.deltaY > 0) volume -= 0.1;
|
||||
if (e.deltaY < 0) volume += 0.1;
|
||||
if (volume < 0) volume = 0;
|
||||
if (volume > 1) volume = 1;
|
||||
if (video != null) {
|
||||
video.muted = (volume == 0);
|
||||
video.volume = volume;
|
||||
}
|
||||
//changeSetting("videovolume", volume);
|
||||
e.preventDefault();
|
||||
}
|
||||
}, false);
|
||||
|
||||
// [play once] vs [loop] controls
|
||||
/*function setupLoopControl(i) {
|
||||
loopControls[i].addEventListener("click", function(e) {
|
||||
loop = (i != 0);
|
||||
thumb.href = thumb.href.replace(/([\?&])loop=\d+/, "$1loop=" + i);
|
||||
if (video != null) {
|
||||
video.loop = loop;
|
||||
if (loop && video.currentTime >= video.duration) {
|
||||
video.currentTime = 0;
|
||||
}
|
||||
}
|
||||
loopControls[i].style.fontWeight = "bold";
|
||||
loopControls[1-i].style.fontWeight = "inherit";
|
||||
}, false);
|
||||
}
|
||||
|
||||
loopControls[0].textContent = _("[play once]");
|
||||
loopControls[1].textContent = _("[loop]");
|
||||
loopControls[(setting("videoloop") ? 1 : 0)].style.fontWeight = "bold";
|
||||
for (var i = 0; i < 2; i++) {
|
||||
setupLoopControl(i);
|
||||
loopControls[i].style.whiteSpace = "nowrap";
|
||||
fileInfo.appendChild(document.createTextNode(" "));
|
||||
fileInfo.appendChild(loopControls[i]);
|
||||
}*/
|
||||
}
|
||||
|
||||
function setupVideosIn(element) {
|
||||
var thumbs = element.querySelectorAll("a.file");
|
||||
for (var i = 0; i < thumbs.length; i++) {
|
||||
if (/(\.webm)|(\.mp4)$/.test(thumbs[i].pathname)) {
|
||||
setupVideo(thumbs[i], thumbs[i].href);
|
||||
} else {
|
||||
var url = thumbs[i].href
|
||||
if (/(\.webm)|(\.mp4)$/.test(url)) setupVideo(thumbs[i], url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onready(function(){
|
||||
// Insert menu from settings.js
|
||||
if (typeof settingsMenu != "undefined" && typeof Options == "undefined")
|
||||
document.body.insertBefore(settingsMenu, document.getElementsByTagName("hr")[0]);
|
||||
|
||||
// Setup Javascript events for videos in document now
|
||||
setupVideosIn(document);
|
||||
|
||||
// Setup Javascript events for videos added by updater
|
||||
if (window.MutationObserver) {
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
for (var i = 0; i < mutations.length; i++) {
|
||||
var additions = mutations[i].addedNodes;
|
||||
if (additions == null) continue;
|
||||
for (var j = 0; j < additions.length; j++) {
|
||||
var node = additions[j];
|
||||
if (node.nodeType == 1) {
|
||||
setupVideosIn(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
observer.observe(document.body, {childList: true, subtree: true});
|
||||
}
|
||||
});
|
||||
|
66
contrib/js/livechan.js
Normal file
66
contrib/js/livechan.js
Normal file
@ -0,0 +1,66 @@
|
||||
function livechan_got_post(widget, j) {
|
||||
// do scroll
|
||||
while (widget.children.length > 5) {
|
||||
// remove top element
|
||||
widget.removeChild(widget.children[0]);
|
||||
}
|
||||
nntpchan_buildpost(widget, j);
|
||||
// scroll to bottom
|
||||
widget.scrollTop = widget.scrollHeight;
|
||||
}
|
||||
|
||||
// inject post form into an element
|
||||
function inject_postform(prefix, parent) {
|
||||
|
||||
}
|
||||
|
||||
// inject livechan widget into parent
|
||||
function inject_livechan_widget(prefix, parent) {
|
||||
if ( "WebSocket" in window ) {
|
||||
var url = "ws://"+document.location.host+prefix+"live";
|
||||
if ( document.location.protocol == "https:" ) {
|
||||
url = "wss://"+document.location.host+prefix+"live";
|
||||
}
|
||||
var socket = new WebSocket(url);
|
||||
var progress = function(str) {
|
||||
parent.innerHTML = "<pre>livechan: "+str+"</pre>";
|
||||
};
|
||||
progress("initialize");
|
||||
socket.onopen = function () {
|
||||
progress("streaming (read only)");
|
||||
}
|
||||
socket.onmessage = function(ev) {
|
||||
var j = null;
|
||||
try {
|
||||
j = JSON.parse(ev.data);
|
||||
} catch(e) {
|
||||
// ignore
|
||||
}
|
||||
if (j) {
|
||||
console.log(j);
|
||||
livechan_got_post(parent, j);
|
||||
}
|
||||
}
|
||||
socket.onclose = function(ev) {
|
||||
progress("connection closed");
|
||||
setTimeout(function() {
|
||||
inject_livechan_widget(prefix, parent);
|
||||
}, 1000);
|
||||
}
|
||||
} else {
|
||||
parent.innerHTML = "<pre>livechan mode requires websocket support</pre>";
|
||||
setTimeout(function() {
|
||||
parent.innerHTML = "";
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function ukko_livechan(prefix) {
|
||||
var ukko = document.getElementById("ukko_threads");
|
||||
if (ukko) {
|
||||
// remove children
|
||||
ukko.innerHTML = "";
|
||||
inject_livechan_widget(prefix, ukko);
|
||||
}
|
||||
}
|
||||
|
10
contrib/js/local_storage.js
Normal file
10
contrib/js/local_storage.js
Normal file
@ -0,0 +1,10 @@
|
||||
function get_storage() {
|
||||
var st = null;
|
||||
if (window.localStorage) {
|
||||
st = window.localStorage;
|
||||
} else if (localStorage) {
|
||||
st = localStorage;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
11
contrib/js/main.js_
Normal file
11
contrib/js/main.js_
Normal file
@ -0,0 +1,11 @@
|
||||
onready_callbacks = [];
|
||||
function onready(fnc) {
|
||||
onready_callbacks.push(fnc);
|
||||
}
|
||||
|
||||
function ready() {
|
||||
for (var i = 0; i < onready_callbacks.length; i++) {
|
||||
onready_callbacks[i]();
|
||||
}
|
||||
}
|
||||
|
15
contrib/js/theme.js
Normal file
15
contrib/js/theme.js
Normal file
@ -0,0 +1,15 @@
|
||||
function enable_theme(prefix, name) {
|
||||
if (prefix && name) {
|
||||
var theme = document.getElementById("current_theme");
|
||||
if (theme) {
|
||||
theme.href = prefix + "static/"+ name + ".css";
|
||||
var st = get_storage();
|
||||
st.nntpchan_prefix = prefix;
|
||||
st.nntpchan_theme = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply themes
|
||||
var st = get_storage();
|
||||
enable_theme(st.nntpchan_prefix, st.nntpchan_theme);
|
BIN
contrib/static/collapse.gif
Normal file
BIN
contrib/static/collapse.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 60 B |
@ -1,228 +1,40 @@
|
||||
//
|
||||
// nntpchan.js -- frontend ui niceness
|
||||
//
|
||||
//For source code and license information please check https://github.com/majestrate/nntpchan
|
||||
|
||||
|
||||
// insert a backlink for a post given its short hash
|
||||
function nntpchan_backlink(shorthash) {
|
||||
var elem = document.getElementById("postform_message");
|
||||
if ( elem )
|
||||
{
|
||||
elem.value += ">>" + shorthash.substr(0,10) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
function get_storage() {
|
||||
var st = null;
|
||||
if (window.localStorage) {
|
||||
st = window.localStorage;
|
||||
} else if (localStorage) {
|
||||
st = localStorage;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
function enable_theme(prefix, name) {
|
||||
if (prefix && name) {
|
||||
var theme = document.getElementById("current_theme");
|
||||
if (theme) {
|
||||
theme.href = prefix + "static/"+ name + ".css";
|
||||
var st = get_storage();
|
||||
st.nntpchan_prefix = prefix;
|
||||
st.nntpchan_theme = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// call an api method
|
||||
// handler(json_object) on success
|
||||
// handler(null) on fail
|
||||
function nntpchan_apicall(url, handler, err_handler) {
|
||||
var ajax = new XMLHttpRequest();
|
||||
ajax.onreadystatechange = function() {
|
||||
if (ajax.readyState == XMLHttpRequest.DONE ) {
|
||||
var status = ajax.status;
|
||||
var j = null;
|
||||
if (status == 200) {
|
||||
// found
|
||||
try {
|
||||
j = JSON.parse(ajax.responseText);
|
||||
} catch (e) {} // ignore parse error
|
||||
} else if (status == 410) {
|
||||
if (err_handler) {err_handler("cannot fetch post: api disabled");}
|
||||
return;
|
||||
}
|
||||
handler(j);
|
||||
}
|
||||
};
|
||||
ajax.open("GET", url);
|
||||
ajax.send();
|
||||
}
|
||||
|
||||
// build post from json
|
||||
// inject into parent
|
||||
// if j is null then inject "not found" post
|
||||
function nntpchan_buildpost(parent, j) {
|
||||
var post = document.createElement("div");
|
||||
if (j) {
|
||||
// huehuehue
|
||||
post.innerHTML = j.PostMarkup;
|
||||
inject_hover_for_element(post);
|
||||
} else {
|
||||
post.setAttribute("class", "notfound post");
|
||||
post.appendChild(document.createTextNode("post not found"));
|
||||
}
|
||||
parent.appendChild(post);
|
||||
}
|
||||
|
||||
// inject post hover behavior
|
||||
function inject_hover(prefix, el, parent) {
|
||||
if (!prefix) { throw "prefix is not defined"; }
|
||||
var linkhash = el.getAttribute("backlinkhash");
|
||||
if (!linkhash) { throw "linkhash undefined"; }
|
||||
console.log("rewrite linkhash "+linkhash);
|
||||
|
||||
var elem = document.createElement("span");
|
||||
elem.setAttribute("class", "backlink_rewritten");
|
||||
elem.appendChild(document.createTextNode(">>"+linkhash.substr(0,10)));
|
||||
if (!parent) {
|
||||
parent = el.parentNode;
|
||||
}
|
||||
parent.removeChild(el);
|
||||
parent.appendChild(elem);
|
||||
|
||||
elem.onclick = function(ev) {
|
||||
if(parent.backlink) {
|
||||
nntpchan_apicall(prefix+"api/find?hash="+linkhash, function(j) {
|
||||
var wrapper = document.createElement("div");
|
||||
wrapper.setAttribute("class", "hover "+linkhash);
|
||||
if (j == null) {
|
||||
// not found?
|
||||
wrapper.setAttribute("class", "hover notfound-hover "+linkhash);
|
||||
wrapper.appendChild(document.createTextNode("not found"));
|
||||
} else {
|
||||
// wrap backlink
|
||||
nntpchan_buildpost(wrapper, j);
|
||||
}
|
||||
parent.appendChild(wrapper);
|
||||
parent.backlink = false;
|
||||
}, function(msg) {
|
||||
var wrapper = document.createElement("div");
|
||||
wrapper.setAttribute("class", "hover "+linkhash);
|
||||
wrapper.appendChild(document.createTextNode(msg));
|
||||
parent.appendChild(wrapper);
|
||||
parent.backlink = false;
|
||||
});
|
||||
} else {
|
||||
var elems = document.getElementsByClassName(linkhash);
|
||||
if (!elems) throw "bad state, no backlinks open?";
|
||||
for (var idx = 0 ; idx < elems.length; idx ++ ) {
|
||||
elems[idx].parentNode.removeChild(elems[idx]);
|
||||
}
|
||||
parent.backlink = true;
|
||||
}
|
||||
};
|
||||
parent.backlink = true;
|
||||
}
|
||||
|
||||
function livechan_got_post(widget, j) {
|
||||
// do scroll
|
||||
while (widget.children.length > 5) {
|
||||
// remove top element
|
||||
widget.removeChild(widget.children[0]);
|
||||
}
|
||||
nntpchan_buildpost(widget, j);
|
||||
// scroll to bottom
|
||||
widget.scrollTop = widget.scrollHeight;
|
||||
}
|
||||
|
||||
// inject post form into an element
|
||||
function inject_postform(prefix, parent) {
|
||||
|
||||
}
|
||||
|
||||
// inject livechan widget into parent
|
||||
function inject_livechan_widget(prefix, parent) {
|
||||
if ( "WebSocket" in window ) {
|
||||
var url = "ws://"+document.location.host+prefix+"live";
|
||||
if ( document.location.protocol == "https:" ) {
|
||||
url = "wss://"+document.location.host+prefix+"live";
|
||||
}
|
||||
var socket = new WebSocket(url);
|
||||
var progress = function(str) {
|
||||
parent.innerHTML = "<pre>livechan: "+str+"</pre>";
|
||||
};
|
||||
progress("initialize");
|
||||
socket.onopen = function () {
|
||||
progress("streaming (read only)");
|
||||
}
|
||||
socket.onmessage = function(ev) {
|
||||
var j = null;
|
||||
try {
|
||||
j = JSON.parse(ev.data);
|
||||
} catch(e) {
|
||||
// ignore
|
||||
}
|
||||
if (j) {
|
||||
console.log(j);
|
||||
livechan_got_post(parent, j);
|
||||
}
|
||||
}
|
||||
socket.onclose = function(ev) {
|
||||
progress("connection closed");
|
||||
setTimeout(function() {
|
||||
inject_livechan_widget(prefix, parent);
|
||||
}, 1000);
|
||||
}
|
||||
} else {
|
||||
parent.innerHTML = "<pre>livechan mode requires websocket support</pre>";
|
||||
setTimeout(function() {
|
||||
parent.innerHTML = "";
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function ukko_livechan(prefix) {
|
||||
var ukko = document.getElementById("ukko_threads");
|
||||
if (ukko) {
|
||||
// remove children
|
||||
ukko.innerHTML = "";
|
||||
inject_livechan_widget(prefix, ukko);
|
||||
}
|
||||
}
|
||||
|
||||
var banner_count = 3;
|
||||
|
||||
// inject a banner into an element
|
||||
function nntpchan_inject_banners(elem, prefix) {
|
||||
var n = Math.floor(Math.random() * banner_count);
|
||||
var banner = prefix + "static/banner_"+n+".jpg";
|
||||
var e = document.createElement("img");
|
||||
e.src = banner;
|
||||
e.id = "nntpchan_banner";
|
||||
elem.appendChild(e);
|
||||
}
|
||||
|
||||
// inject post hover for all backlinks in an element
|
||||
function inject_hover_for_element(elem) {
|
||||
var elems = elem.getElementsByClassName("backlink");
|
||||
var ls = [];
|
||||
var l = elems.length;
|
||||
for ( var idx = 0 ; idx < l ; idx ++ ) {
|
||||
var e = elems[idx];
|
||||
ls.push(e);
|
||||
}
|
||||
for( var elem in ls ) {
|
||||
inject_hover(prefix, ls[elem]);
|
||||
}
|
||||
}
|
||||
|
||||
function init(prefix) {
|
||||
// inject posthover ...
|
||||
inject_hover_for_element(document);
|
||||
}
|
||||
|
||||
// apply themes
|
||||
var st = get_storage();
|
||||
enable_theme(st.nntpchan_prefix, st.nntpchan_theme);
|
||||
onready_callbacks=[];function onready(fnc){onready_callbacks.push(fnc);}
|
||||
function ready(){for(var i=0;i<onready_callbacks.length;i++){onready_callbacks[i]();}}function nntpchan_apicall(url,handler,err_handler){var ajax=new XMLHttpRequest();ajax.onreadystatechange=function(){if(ajax.readyState==XMLHttpRequest.DONE){var status=ajax.status;var j=null;if(status==200){try{j=JSON.parse(ajax.responseText);}catch(e){}}else if(status==410){if(err_handler){err_handler("cannot fetch post: api disabled");}
|
||||
return;}
|
||||
handler(j);}};ajax.open("GET",url);ajax.send();}
|
||||
function nntpchan_buildpost(parent,j){var post=document.createElement("div");if(j){post.innerHTML=j.PostMarkup;inject_hover_for_element(post);}else{post.setAttribute("class","notfound post");post.appendChild(document.createTextNode("post not found"));}
|
||||
parent.appendChild(post);}function nntpchan_backlink(shorthash){var elem=document.getElementById("postform_message");if(elem)
|
||||
{elem.value+=">>"+shorthash.substr(0,10)+"\n";}}
|
||||
function inject_hover(prefix,el,parent){if(!prefix){throw"prefix is not defined";}
|
||||
var linkhash=el.getAttribute("backlinkhash");if(!linkhash){throw"linkhash undefined";}
|
||||
console.log("rewrite linkhash "+linkhash);var elem=document.createElement("span");elem.setAttribute("class","backlink_rewritten");elem.appendChild(document.createTextNode(">>"+linkhash.substr(0,10)));if(!parent){parent=el.parentNode;}
|
||||
parent.removeChild(el);parent.appendChild(elem);elem.onclick=function(ev){if(parent.backlink){nntpchan_apicall(prefix+"api/find?hash="+linkhash,function(j){var wrapper=document.createElement("div");wrapper.setAttribute("class","hover "+linkhash);if(j==null){wrapper.setAttribute("class","hover notfound-hover "+linkhash);wrapper.appendChild(document.createTextNode("not found"));}else{nntpchan_buildpost(wrapper,j);}
|
||||
parent.appendChild(wrapper);parent.backlink=false;},function(msg){var wrapper=document.createElement("div");wrapper.setAttribute("class","hover "+linkhash);wrapper.appendChild(document.createTextNode(msg));parent.appendChild(wrapper);parent.backlink=false;});}else{var elems=document.getElementsByClassName(linkhash);if(!elems)throw"bad state, no backlinks open?";for(var idx=0;idx<elems.length;idx++){elems[idx].parentNode.removeChild(elems[idx]);}
|
||||
parent.backlink=true;}};parent.backlink=true;}
|
||||
function inject_hover_for_element(elem){var elems=elem.getElementsByClassName("backlink");var ls=[];var l=elems.length;for(var idx=0;idx<l;idx++){var e=elems[idx];ls.push(e);}
|
||||
for(var elem in ls){inject_hover(prefix,ls[elem]);}}
|
||||
function init(prefix){inject_hover_for_element(document);}var banner_count=3;function nntpchan_inject_banners(elem,prefix){var n=Math.floor(Math.random()*banner_count);var banner=prefix+"static/banner_"+n+".jpg";var e=document.createElement("img");e.src=banner;e.id="nntpchan_banner";elem.appendChild(e);}var configRoot="";if(typeof _=='undefined'){var _=function(a){return a;};}
|
||||
function setupVideo(thumb,url){if(thumb.videoAlreadySetUp)return;thumb.videoAlreadySetUp=true;var video=null;var videoContainer,videoHide;var expanded=false;var hovering=false;var loop=true;var loopControls=[document.createElement("span"),document.createElement("span")];var fileInfo=thumb.parentNode.querySelector(".fileinfo");var mouseDown=false;function unexpand(){if(expanded){expanded=false;if(video.pause)video.pause();videoContainer.style.display="none";thumb.style.display="inline";video.style.maxWidth="inherit";video.style.maxHeight="inherit";}}
|
||||
function unhover(){if(hovering){hovering=false;if(video.pause)video.pause();videoContainer.style.display="none";video.style.maxWidth="inherit";video.style.maxHeight="inherit";}}
|
||||
function getVideo(){if(video==null){video=document.createElement("video");video.src=url;video.loop=loop;video.innerText=_("Your browser does not support HTML5 video.");videoHide=document.createElement("img");videoHide.src=configRoot+"static/collapse.gif";videoHide.alt="[ - ]";videoHide.title="Collapse video";videoHide.style.marginLeft="-15px";videoHide.style.cssFloat="left";videoHide.addEventListener("click",unexpand,false);videoContainer=document.createElement("div");videoContainer.style.paddingLeft="15px";videoContainer.style.display="none";videoContainer.appendChild(videoHide);videoContainer.appendChild(video);thumb.parentNode.insertBefore(videoContainer,thumb.nextSibling);video.addEventListener("mousedown",function(e){if(e.button==0)mouseDown=true;},false);video.addEventListener("mouseup",function(e){if(e.button==0)mouseDown=false;},false);video.addEventListener("mouseenter",function(e){mouseDown=false;},false);video.addEventListener("mouseout",function(e){if(mouseDown&&e.clientX-video.getBoundingClientRect().left<=0){unexpand();}
|
||||
mouseDown=false;},false);}}
|
||||
thumb.addEventListener("click",function(e){if(!e.shiftKey&&!e.ctrlKey&&!e.altKey&&!e.metaKey){getVideo();expanded=true;hovering=false;video.style.position="static";video.style.pointerEvents="inherit";video.style.display="inline";videoHide.style.display="inline";videoContainer.style.display="block";videoContainer.style.position="static";video.parentNode.parentNode.removeAttribute('style');thumb.style.display="none";video.controls=true;if(video.readyState==0){video.addEventListener("loadedmetadata",expand2,false);}else{setTimeout(expand2,0);}
|
||||
video.play();e.preventDefault();}},false);function expand2(){video.style.maxWidth="100%";video.style.maxHeight=window.innerHeight+"px";var bottom=video.getBoundingClientRect().bottom;if(bottom>window.innerHeight){window.scrollBy(0,bottom-window.innerHeight);}}
|
||||
thumb.addEventListener("mouseover",function(e){if(false){getVideo();expanded=false;hovering=true;var docRight=document.documentElement.getBoundingClientRect().right;var thumbRight=thumb.querySelector("img, video").getBoundingClientRect().right;var maxWidth=docRight-thumbRight-20;if(maxWidth<250)maxWidth=250;video.style.position="fixed";video.style.right="0px";video.style.top="0px";var docRight=document.documentElement.getBoundingClientRect().right;var thumbRight=thumb.querySelector("img, video").getBoundingClientRect().right;video.style.maxWidth=maxWidth+"px";video.style.maxHeight="100%";video.style.pointerEvents="none";video.style.display="inline";videoHide.style.display="none";videoContainer.style.display="inline";videoContainer.style.position="fixed";video.controls=false;video.play();}},false);thumb.addEventListener("mouseout",unhover,false);thumb.addEventListener("wheel",function(e){if(true){if(e.deltaY>0)volume-=0.1;if(e.deltaY<0)volume+=0.1;if(volume<0)volume=0;if(volume>1)volume=1;if(video!=null){video.muted=(volume==0);video.volume=volume;}
|
||||
e.preventDefault();}},false);}
|
||||
function setupVideosIn(element){var thumbs=element.querySelectorAll("a.file");for(var i=0;i<thumbs.length;i++){if(/(\.webm)|(\.mp4)$/.test(thumbs[i].pathname)){setupVideo(thumbs[i],thumbs[i].href);}else{var url=thumbs[i].href
|
||||
if(/(\.webm)|(\.mp4)$/.test(url))setupVideo(thumbs[i],url);}}}
|
||||
onready(function(){if(typeof settingsMenu!="undefined"&&typeof Options=="undefined")
|
||||
document.body.insertBefore(settingsMenu,document.getElementsByTagName("hr")[0]);setupVideosIn(document);if(window.MutationObserver){var observer=new MutationObserver(function(mutations){for(var i=0;i<mutations.length;i++){var additions=mutations[i].addedNodes;if(additions==null)continue;for(var j=0;j<additions.length;j++){var node=additions[j];if(node.nodeType==1){setupVideosIn(node);}}}});observer.observe(document.body,{childList:true,subtree:true});}});function livechan_got_post(widget,j){while(widget.children.length>5){widget.removeChild(widget.children[0]);}
|
||||
nntpchan_buildpost(widget,j);widget.scrollTop=widget.scrollHeight;}
|
||||
function inject_postform(prefix,parent){}
|
||||
function inject_livechan_widget(prefix,parent){if("WebSocket"in window){var url="ws://"+document.location.host+prefix+"live";if(document.location.protocol=="https:"){url="wss://"+document.location.host+prefix+"live";}
|
||||
var socket=new WebSocket(url);var progress=function(str){parent.innerHTML="<pre>livechan: "+str+"</pre>";};progress("initialize");socket.onopen=function(){progress("streaming (read only)");}
|
||||
socket.onmessage=function(ev){var j=null;try{j=JSON.parse(ev.data);}catch(e){}
|
||||
if(j){console.log(j);livechan_got_post(parent,j);}}
|
||||
socket.onclose=function(ev){progress("connection closed");setTimeout(function(){inject_livechan_widget(prefix,parent);},1000);}}else{parent.innerHTML="<pre>livechan mode requires websocket support</pre>";setTimeout(function(){parent.innerHTML="";},5000);}}
|
||||
function ukko_livechan(prefix){var ukko=document.getElementById("ukko_threads");if(ukko){ukko.innerHTML="";inject_livechan_widget(prefix,ukko);}}function get_storage(){var st=null;if(window.localStorage){st=window.localStorage;}else if(localStorage){st=localStorage;}
|
||||
return st;}function enable_theme(prefix,name){if(prefix&&name){var theme=document.getElementById("current_theme");if(theme){theme.href=prefix+"static/"+name+".css";var st=get_storage();st.nntpchan_prefix=prefix;st.nntpchan_theme=name;}}}
|
||||
var st=get_storage();enable_theme(st.nntpchan_prefix,st.nntpchan_theme);
|
@ -59,6 +59,7 @@
|
||||
var e = document.getElementById("nntpchan_banner");
|
||||
nntpchan_inject_banners(e, prefix);
|
||||
init(prefix);
|
||||
ready();
|
||||
</script>
|
||||
<hr/>
|
||||
<footer>
|
||||
|
@ -22,7 +22,7 @@
|
||||
{{#post.Attachments}}
|
||||
<figure>
|
||||
<figcaption>
|
||||
<a href="{{Source}}" title="{{Filename}}" target="_blank"><img src="{{Thumbnail}}" alt="{{Filename}}" class="thumbnail"/></a>
|
||||
<a class="file" href="{{Source}}" title="{{Filename}}" target="_blank"><img src="{{Thumbnail}}" alt="{{Filename}}" class="thumbnail"/></a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
{{/post.Attachments}}
|
||||
|
@ -49,6 +49,7 @@
|
||||
var e = document.getElementById("nntpchan_banner");
|
||||
nntpchan_inject_banners(e, prefix);
|
||||
init(prefix);
|
||||
ready();
|
||||
</script>
|
||||
<hr/>
|
||||
<footer>
|
||||
|
@ -41,6 +41,7 @@
|
||||
var e = document.getElementById("nntpchan_banner");
|
||||
nntpchan_inject_banners(e, prefix);
|
||||
init(prefix);
|
||||
ready();
|
||||
</script>
|
||||
<hr/>
|
||||
<footer>
|
||||
|
Reference in New Issue
Block a user