2016-04-27 17:21:12 +05:00
//For source code and license information please check https://github.com/majestrate/nntpchan
2016-04-30 18:58:21 +05:00
/* ./contrib/js/main.js_ */
2016-04-27 18:36:57 +05:00
onready _callbacks = [ ] ; function onready ( fnc ) { onready _callbacks . push ( fnc ) ; }
2016-04-30 18:58:21 +05: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 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" ) ) ; }
2016-04-30 18:58:21 +05:00
parent . appendChild ( post ) ; }
/* ./contrib/js/backlink.js */
function nntpchan _backlink ( shorthash ) { var elem = document . getElementById ( "postform_message" ) ; if ( elem )
2016-04-27 17:21:12 +05: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 18:58:21 +05: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 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 18:58: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 } ) ; } } ) ;
/* ./contrib/js/expand-video.js */
var configRoot = "" ; if ( typeof _ == 'undefined' ) { var _ = function ( a ) { return a ; } ; }
2016-04-30 17:40:21 +05: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 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" )
2016-04-30 18:58:21 +05: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 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 ) ; } }
2016-04-30 18:58:21 +05: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 17:21:12 +05:00
var st = get _storage ( ) ; enable _theme ( st . nntpchan _prefix , st . nntpchan _theme ) ;