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/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/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 */
2016-05-01 17:56:47 -04:00
function filenameIsImage ( fname ){ return /\.(gif|jpeg|jpg|png|webp)/ . test ( fname . toLowerCase ());}
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 ;}
2016-05-03 12:17:08 -04:00
/* ./contrib/js/reply.js */
2016-05-03 14:27:07 -04:00
function getReplyTo (){ if ( ! document . dynreply ){ var e = document . getElementById ( "postform_container" ); if ( e ){ document . dynreply = new DynReply ( e );} else { document . dynreply = new DynReply ();}}
return document . dynreply ;}
2016-05-03 12:17:08 -04:00
function table_insert_row ( table , header , items ){ var tr = document . createElement ( "tr" ); var th = document . createElement ( "th" ); th . appendChild ( header ); tr . appendChild ( th ); for ( var idx = 0 ; idx < items . length ; idx ++ ){ var elem = document . createElement ( "td" ); elem . appendChild ( items [ idx ]); tr . appendChild ( elem );}
table . appendChild ( tr );}
2016-05-03 14:22:10 -04:00
function DynReply ( existingElem ){ if ( existingElem ){ this . elem = existingElem ; this . form = this . elem . querySelector ( "form" ); this . _error = document . getElementById ( "postform_msg" ); this . url = this . form . action + "?t=json" ; this . x = 1 ; this . y = 1 ; return ;}
2016-05-03 12:17:08 -04:00
var elem = document . createElement ( "div" ); elem . setAttribute ( "id" , "postform_container" ); this . elem = elem ; this . form = document . createElement ( "form" ); this . form . enctype = "multipart/form-data" ; this . form . name = "post" ; this . form . method = "post" ; elem = document . createElement ( "input" ); elem . setAttribute ( "id" , "postform_reference" ); elem . name = "reference" ; elem . type = "hidden" ; this . form . appendChild ( elem ); var table = document . createElement ( "table" ); table . setAttribute ( "class" , "postform" ); var tbody = document . createElement ( "tbody" ); var span = document . createElement ( "span" ); elem = document . createElement ( "input" ); elem . setAttribute ( "name" , "name" ); elem . setAttribute ( "value" , "Anonymous" ); elem . setAttribute ( "id" , "postform_name" ); span . appendChild ( elem ); var err_elem = document . createElement ( "span" ); err_elem . setAttribute ( "id" , "postform_msg" ); span . appendChild ( err_elem ); this . _error = err_elem ; table_insert_row ( tbody , document . createTextNode ( "Name" ),[ span ])
elem = document . createElement ( "input" ); elem . setAttribute ( "name" , "subject" ); elem . setAttribute ( "value" , "" ); elem . setAttribute ( "id" , "postform_subject" ); var submit = document . createElement ( "input" ); submit . setAttribute ( "value" , "reply" ); submit . setAttribute ( "class" , "button" ); submit . setAttribute ( "type" , "submit" ); submit . setAttribute ( "id" , "postform_submit" ); table_insert_row ( tbody , document . createTextNode ( "Subject" ),[ elem , submit ]); elem = document . createElement ( "textarea" ); elem . setAttribute ( "id" , "postform_message" ); elem . setAttribute ( "name" , "message" ); elem . setAttribute ( "cols" , "40" ); elem . setAttribute ( "rows" , "5" ); table_insert_row ( tbody , document . createTextNode ( "Comment" ),[ elem ]); elem = document . createElement ( "input" ); elem . setAttribute ( "class" , "postform_attachment" ); elem . setAttribute ( "id" , "postform_attachments" ); elem . setAttribute ( "type" , "file" ); elem . setAttribute ( "name" , "attachment_uploaded" ); elem . setAttribute ( "multiple" , "multiple" ); table_insert_row ( tbody , document . createTextNode ( "Files" ),[ elem ]); elem = document . createElement ( "input" ); elem . setAttribute ( "type" , "checkbox" ); elem . setAttribute ( "name" , "dubs" ); table_insert_row ( tbody , document . createTextNode ( "Get Dubs" ),[ elem ]); elem = document . createElement ( "img" ); elem . setAttribute ( "id" , "captcha_img" ); elem . alt = "captcha" ; table_insert_row ( tbody , document . createTextNode ( "Captcha" ),[ elem ]); elem = document . createElement ( "input" ); elem . name = "captcha" ; elem . autocomplete = "off" ; elem . setAttribute ( "id" , "captcha_solution" ); table_insert_row ( tbody , document . createTextNode ( "Solution" ),[ elem ])
2016-05-03 14:22:10 -04:00
table . appendChild ( tbody ); this . form . appendChild ( table ); this . elem . appendChild ( this . form ); document . body . appendChild ( this . elem ); this . board = null ; this . roothash = null ; this . prefix = null ; this . url = null ; this . x = 1 ; this . y = 1 ;}
2016-05-03 14:16:15 -04:00
DynReply . prototype . getX = function (){ return this . x ;}
DynReply . prototype . getY = function (){ return this . y ;}
2016-05-03 14:19:16 -04:00
DynReply . prototype . translate = function ( dx , dy ){ if ( this . x && this . y ){ var x = this . x + dx ; var y = this . y + dy ; this . moveTo ( x , y );};}
2016-05-03 14:23:45 -04:00
DynReply . prototype . moveTo = function ( x , y ){ console . log ( "moveto" , x , y ); if ( x && y ){ var nx = document . body . clientLeft - x ; if ( nx > 0 && y > 0 && nx < document . body . clientWidth && y < document . body . clientHeight ){ this . elem . setAttribute ( "style" , "top: " + y + "px; right: " + nx + "px;" ); this . x = x ; this . y = y ;}} else { console . log ( "!!" , x , y );}}
2016-05-03 12:17:08 -04:00
DynReply . prototype . update = function (){ if ( this . prefix ){ this . updateCaptcha (); if ( this . board && this . roothash ){ var ref = document . getElementById ( "postform_reference" ); ref . setAttribute ( "value" , this . roothash ); this . url = this . prefix + "post/" + this . board + "?t=json" ;}}}
DynReply . prototype . show = function (){ console . log ( "show dynreply" ); this . update (); this . elem . style . display = 'inline' ;}
DynReply . prototype . hide = function (){ console . log ( "hide dynreply" ); this . elem . style . display = "none" ;}
DynReply . prototype . clear = function (){ this . clearSolution (); this . clearPostbox ();}
DynReply . prototype . clearSolution = function (){ var e = document . getElementById ( "captcha_solution" ); e . value = "" ;}
DynReply . prototype . clearPostbox = function (){ var e = document . getElementById ( "postform_subject" ); e . value = "" ; e = document . getElementById ( "postform_message" ); e . value = "" ; e = document . getElementById ( "postform_attachments" ); e . value = null ;}
DynReply . prototype . post = function ( cb , err_cb ){ if ( this . url && this . form ){ var data = new FormData ( this . form ); var ajax = new XMLHttpRequest (); ajax . onreadystatechange = function ( ev ){ if ( ajax . readyState == XMLHttpRequest . DONE ){ var j = null ; try { j = JSON . parse ( ajax . responseText ); cb ( j );} catch ( e ){ if ( err_cb ){ err_cb ( e );}}}}
ajax . open ( "POST" , this . url ); ajax . send ( data );}}
DynReply . prototype . updateCaptcha = function (){ if ( this . prefix ){ var captcha_img = document . getElementById ( "captcha_img" ); captcha_img . src = this . prefix + "captcha/img" ;}
this . clearSolution ();}
DynReply . prototype . setPrefix = function ( prefix ){ this . prefix = prefix ;}
DynReply . prototype . hide = function (){ this . elem . style . display = 'none' ;}
DynReply . prototype . setBoard = function ( boardname ){ if ( boardname ){ this . board = boardname ;}}
DynReply . prototype . setRoot = function ( roothash ){ if ( roothash ){ this . roothash = roothash ;}}
2016-05-03 12:28:19 -04:00
DynReply . prototype . showError = function ( msg ){ console . log ( "error in dynreply: " + msg ); this . _error . setAttribute ( "class" , "error message" ); this . _error . appendChild ( document . createTextNode ( msg )); this . updateCaptcha ();}
2016-05-03 12:17:08 -04:00
DynReply . prototype . showMessage = function ( msg ){ this . _error . setAttribute ( "class" , "message" ); this . _error . innerHTML = "" ; this . _error . appendChild ( document . createTextNode ( msg )); var e = this . _error ; setTimeout ( function (){ e . innerHTML = "" ;}, 2000 );}
function nntpchan_reply ( parent , shorthash ){ if ( parent ){ var boardname = parent . getAttribute ( "boardname" ); var roothash = parent . getAttribute ( "root" ); var replyto = getReplyTo (); replyto . setBoard ( boardname ); replyto . setRoot ( roothash ); replyto . show ();}
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-05-03 14:34:40 -04:00
function init ( prefix ){ inject_hover_for_element ( document ); var rpl = getReplyTo (); rpl . setPrefix ( prefix ); var e = rpl . elem ; var mouseDownX , mouseDownY ; var ox = document . body . clientWidth - 50 ; var oy = 10 ; rpl . moveTo ( ox , oy ); e . setAttribute ( "draggable" , "true" ); e . addEventListener ( "dragstart" , function ( ev ){ console . log ( ev ); mouseDownX = ev . screenX ; mouseDownY = ev . screenY ; if ( ! ev . shiftKey ){ ev . preventDefault ();}}, false ); e . addEventListener ( "dragend" , function ( ev ){ var rpl = getReplyTo (); console . log ( mouseDownX , mouseDownY ); var ox = rpl . getX (); var oy = rpl . getY (); var dx = ox + ev . screenX - mouseDownX ; var dy = oy + ev . screenY - mouseDownY ; console . log ( ox , oy , dx , dy ); rpl . translate ( dx , dy );}, false ); e = document . getElementById ( "postform_submit" ); var postit = function (){ var f = document . querySelector ( "form" ); var r = getReplyTo (); r . showMessage ( "posting... " ); r . post ( function ( j ){ if ( j . error ){ r . showError ( j . error );} else { r . showMessage ( "posted :^)" ); r . updateCaptcha (); r . clear ();}}, function ( err ){ r . showError ( err ); r . clearSolution ();});}
2016-05-03 12:17:08 -04:00
var f = document . querySelector ( "form" ); f . onsubmit = function (){ postit (); return false ;}}
2016-04-30 09:58:21 -04:00
/* ./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 );