2016-04-27 14:21:12 +02:00
//For source code and license information please check https://github.com/majestrate/nntpchan
2015-09-04 17:09:43 -04:00
2016-04-30 09:58:21 -04:00
/* ./contrib/js/main.js_ */
2016-04-27 15:36:57 +02:00
onready_callbacks = []; function onready ( fnc ){ onready_callbacks . push ( fnc );}
2016-04-30 09:58:21 -04:00
function ready (){ for ( var i = 0 ; i < onready_callbacks . length ; i ++ ){ onready_callbacks [ i ]();}}
/* ./contrib/js/contrib/MathJax/MathJax.js */
if ( document . getElementById && document . childNodes && document . createElement ){ if ( ! ( window . MathJax && MathJax . Hub )){ if ( window . MathJax ){ window . MathJax = { AuthorConfig : window . MathJax }} else { window . MathJax = {}} MathJax . isPacked = true ; MathJax . version = "2.6.1" ; MathJax . fileversion = "2.6.1" ; MathJax . cdnVersion = "2.6.1" ; MathJax . cdnFileVersions = {};( function ( d ){ var b = window [ d ]; if ( ! b ){ b = window [ d ] = {}} var e = []; var c = function ( f ){ var g = f . constructor ; if ( ! g ){ g = function (){}} for ( var h in f ){ if ( h !== "constructor" && f . hasOwnProperty ( h )){ g [ h ] = f [ h ]}} return g }; var a = function (){ return function (){ return arguments . callee . Init . call ( this , arguments )}}; b . Object = c ({ constructor : a (), Subclass : function ( f , h ){ var g = a (); g . SUPER = this ; g . Init = this . Init ; g . Subclass = this . Subclass ; g . Augment = this . Augment ; g . protoFunction = this . protoFunction ; g . can = this . can ; g . has = this . has ; g . isa = this . isa ; g . prototype = new this ( e ); g . prototype . constructor = g ; g . Augment ( f , h ); return g }, Init : function ( f ){ var g = this ; if ( f . length === 1 && f [ 0 ] === e ){ return g } if ( ! ( g instanceof f . callee )){ g = new f . callee ( e )} return g . Init . apply ( g , f ) || g }, Augment : function ( f , g ){ var h ; if ( f != null ){ for ( h in f ){ if ( f . hasOwnProperty ( h )){ this . protoFunction ( h , f [ h ])}} if ( f . toString !== this . prototype . toString && f . toString !== {}. toString ){ this . protoFunction ( "toString" , f . toString )}} if ( g != null ){ for ( h in g ){ if ( g . hasOwnProperty ( h )){ this [ h ] = g [ h ]}}} return this }, protoFunction : function ( g , f ){ this . prototype [ g ] = f ; if ( typeof f === "function" ){ f . SUPER = this . SUPER . prototype }}, prototype : { Init : function (){}, SUPER : function ( f ){ return f . callee . SUPER }, can : function ( f ){ return typeof ( this [ f ]) === "function" }, has : function ( f ){ return typeof ( this [ f ]) !== "undefined" }, isa : function ( f ){ return ( f instanceof Object ) && ( this instanceof f )}}, can : function ( f ){ return this . prototype . can . call ( this , f )}, has : function ( f ){ return this . prototype . has . call ( this , f )}, isa : function ( g ){ var f = this ; while ( f ){ if ( f === g ){ return true } else { f = f . SUPER }} return false }, SimpleSUPER : c ({ constructor : function ( f ){ return this . SimpleSUPER . define ( f )}, define : function ( f ){ var h = {}; if ( f != null ){ for ( var g in f ){ if ( f . hasOwnProperty ( g )){ h [ g ] = this . wrap ( g , f [ g ])}} if ( f . toString !== this . prototype . toString && f . toString !== {}. toString ){ h . toString = this . wrap ( "toString" , f . toString )}} return h }, wrap : function ( i , h ){ if ( typeof ( h ) !== "function" ||! h . toString (). match ( /\.\s*SUPER\s*\(/ )){ return h } var g = function (){ this . SUPER = g . SUPER [ i ]; try { var f = h . apply ( this , arguments )} catch ( j ){ delete this . SUPER ; throw j } delete this . SUPER ; return f }; g . toString = function (){ return h . toString . apply ( h , arguments )}; return g }})})})( "MathJax" );( function ( BASENAME ){ var BASE = window [ BASENAME ]; if ( ! BASE ){ BASE = window [ BASENAME ] = {}} var CALLBACK = function ( data ){ var cb = function (){ return arguments . callee . execute . apply ( arguments . callee , arguments )}; for ( var id in CALLBACK . prototype ){ if ( CALLBACK . prototype . hasOwnProperty ( id )){ if ( typeof ( data [ id ]) !== "undefined" ){ cb [ id ] = data [ id ]} else { cb [ id ] = CALLBACK . prototype [ id ]}}} cb . toString = CALLBACK . prototype . toString ; return cb }; CALLBACK . prototype = { isCallback : true , hook : function (){}, data : [], object : window , execute : function (){ if ( ! this . called || this . autoReset ){ this . called =! this . autoReset ; return this . hook . apply ( this . object , this . data . concat ([]. slice . call ( arguments , 0 )))}}, reset : function (){ delete this . called }, toString : function (){ return this . hook . toString . apply ( this . hook , arguments )}}; var ISCALLBACK = function ( f ){ return ( typeof ( f ) === "function" && f . isCallback )}; var EVAL = function ( code ){ return eval . call ( window , code )}; var TESTEVAL = function (){ EVAL ( "var __TeSt_VaR__ = 1" ); if ( window . __TeSt_VaR__ ){ try { delete window . __TeSt_VaR__ } catch ( error ){ window . __TeSt_VaR__ = null }} else { if ( window . execScript ){ EVAL = function ( code ){ BASE . __code = code ; code = "try {" + BASENAME + ".__result = eval(" + BASENAME + ".__code)} catch(err) {" + BASENAME + ".__result = err}" ; window . execScript ( code ); var result = BASE . __result ; delete BASE . __result ; delete BASE . __code ; if ( result instanceof Error ){ throw result } return result }} else { EVAL = function ( code ){ BASE . __code = code ; code = "try {" + BASENAME + ".__result = eval(" + BASENAME + ".__code)} catch(err) {" + BASENAME + ".__result = err}" ; var head = ( document . getElementsByTagName ( "head" ))[ 0 ]; if ( ! head ){ head = document . body } var script = document
/* ./contrib/js/api.js */
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 14:21:12 +02: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" ));}
2016-04-30 09:58:21 -04:00
parent . appendChild ( post );}
/* ./contrib/js/backlink.js */
function nntpchan_backlink ( shorthash ){ var elem = document . getElementById ( "postform_message" ); if ( elem )
2016-04-27 14:21:12 +02:00
{ 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 09:58:21 -04:00
function init ( prefix ){ inject_hover_for_element ( document );}
/* ./contrib/js/banner.js */
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 );}
/* ./contrib/js/expand-image.js */
function filenameIsImage ( fname ){ return /\.(gif|jpeg|jpg|png|webp)/ . test ( fname );}
2016-04-30 08:51:49 -04: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 08:42:54 -04:00
return false ;}}
2016-04-30 08:32:28 -04: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 09:58:21 -04: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 });}});
/* ./contrib/js/expand-video.js */
var configRoot = "" ; if ( typeof _ == 'undefined' ){ var _ = function ( a ){ return a ;};}
2016-04-30 08:40:21 -04:00
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 15:36:57 +02: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 08:40:21 -04: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 15:36:57 +02:00
onready ( function (){ if ( typeof settingsMenu != "undefined" && typeof Options == "undefined" )
2016-04-30 09:58:21 -04:00
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 });}});
/* ./contrib/js/livechan.js */
function livechan_got_post ( widget , j ){ while ( widget . children . length > 5 ){ widget . removeChild ( widget . children [ 0 ]);}
2016-04-27 14:21:12 +02: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 08:26:14 -04:00
if ( j ){ livechan_got_post ( parent , j );}}
2016-04-27 14:21:12 +02: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 );}}
2016-04-30 09:58:21 -04:00
function ukko_livechan ( prefix ){ var ukko = document . getElementById ( "ukko_threads" ); if ( ukko ){ ukko . innerHTML = "" ; inject_livechan_widget ( prefix , ukko );}}
/* ./contrib/js/local_storage.js */
function get_storage (){ var st = null ; if ( window . localStorage ){ st = window . localStorage ;} else if ( localStorage ){ st = localStorage ;}
return st ;}
/* ./contrib/js/theme.js */
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 ;}}}
2016-04-27 14:21:12 +02:00
var st = get_storage (); enable_theme ( st . nntpchan_prefix , st . nntpchan_theme );