2016-04-27 17:21:12 +05:00
//For source code and license information please check https://github.com/majestrate/nntpchan
2016-04-27 18:36:57 +05:00
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" ) ; }
2016-04-27 17:21:12 +05:00
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 ] ) ; } }
2016-04-30 17:30:14 +05:00
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 ) ; } function filenameIsImage ( fname ) { return /\.(gif|jpeg|jpg|png|webp)/ . test ( fname ) ; }
2016-04-30 17:51:49 +05:00
function setupInlineImage ( thumb , url ) { if ( thumb . inlineIsSetUp ) return ; thumb . inlineIsSetUp = true ; var img = thumb . querySelector ( "img.thumbnail" ) ; var expanded = false ; var oldurl = img . src ; thumb . onclick = function ( ) { if ( expanded ) { img . setAttribute ( "class" , "thumbnail" ) ; img . src = oldurl ; expanded = false ; } else { img . setAttribute ( "class" , "expanded-thumbnail" ) ; img . src = url ; expanded = true ; }
2016-04-30 17:42:54 +05:00
return false ; } }
2016-04-30 17:32:28 +05:00
function setupInlineImageIn ( element ) { var thumbs = element . querySelectorAll ( "a.file" ) ; for ( var i = 0 ; i < thumbs . length ; i ++ ) { var url = thumbs [ i ] . href ; if ( filenameIsImage ( url ) ) { console . log ( "matched url" , url ) ; setupInlineImage ( thumbs [ i ] , url ) ; } } }
2016-04-30 17:40:21 +05:00
onready ( function ( ) { setupInlineImageIn ( 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 ) { setupInlineImageIn ( node ) ; } } } } ) ; observer . observe ( document . body , { childList : true , subtree : true } ) ; } } ) ; 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" ; } }
2016-04-27 18:36:57 +05:00
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 ) ; }
2016-04-30 17:40:21 +05:00
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 ) ; } } }
2016-04-27 18:36:57 +05:00
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 ] ) ; }
2016-04-27 17:21:12 +05:00
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 ) { }
2016-04-30 17:26:14 +05:00
if ( j ) { livechan _got _post ( parent , j ) ; } }
2016-04-27 17:21:12 +05:00
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 ) ;