@ -11,7 +11,7 @@
// @exclude http*://archive.nyafuu.org/bant/statistics/
// @exclude http*://archive.nyafuu.org/bant/statistics/
// @exclude http*://archived.moe/bant/statistics/
// @exclude http*://archived.moe/bant/statistics/
// @exclude http*://thebarchive.com/bant/statistics/
// @exclude http*://thebarchive.com/bant/statistics/
// @version 1.4. 0
// @version 1.4. 1
// @grant GM.xmlHttpRequest
// @grant GM.xmlHttpRequest
// @grant GM.getValue
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.setValue
@ -27,7 +27,7 @@
// see the LICENSE file or <https://www.gnu.org/licenses/>
// see the LICENSE file or <https://www.gnu.org/licenses/>
// Change this if you want verbose debuging information in the console.
// Change this if you want verbose debuging information in the console.
const debugMode = tru e;
const debugMode = fals e;
// For idiots using GM4. Does anyone else not support GM_ functions?
// For idiots using GM4. Does anyone else not support GM_ functions?
if ( typeof GM === 'undefined' ) {
if ( typeof GM === 'undefined' ) {
@ -40,21 +40,21 @@ if (typeof GM === 'undefined') {
//
//
// DO NOT EDIT ANYTHING IN THIS SCRIPT DIRECTLY - YOUR FLAGS SHOULD BE CONFIGURED USING THE FLAG SELECT
// DO NOT EDIT ANYTHING IN THIS SCRIPT DIRECTLY - YOUR FLAGS SHOULD BE CONFIGURED USING THE FLAG SELECT
//
//
const postRemoveCounter = 60 ;
const requestRetryInterval = 5000 ; // TODO: maybe a max retries counter as well?
const version = 2 ; // Breaking changes.
const version = 2 ; // Breaking changes.
const back _end = 'https://flags.plum.moe/' ;
const back _end = 'https://flags.plum.moe/' ;
const api _flags = 'api/flags' ;
const api _flags = 'api/flags' ;
const flag _dir = 'flags/' ;
const flag _dir = 'flags/' ;
const api _get = 'api/get' ;
const api _get = 'api/get' ;
const api _post = 'api/post' ;
const api _post = 'api/post' ;
const namespace = 'BintFlegs' ;
// If you increase this the server will ignore your post.
// If you increase this the server will ignore your post.
const max _flags = 30 ;
const max _flags = 30 ;
var regions = [ ] ; // The flags we have selected.
let regions = [ ] ; // The flags we have selected.
var postNrs = [ ] ; // all post numbers in the thread.
let postNrs = [ ] ; // all post numbers in the thread.
var board _id = "" ; // The board we get flags for.
let board _id = "" ; // The board we get flags for.
let flagsLoaded = false ;
//
//
// DO NOT EDIT ANYTHING IN THIS SCRIPT DIRECTLY - YOUR FLAGS SHOULD BE CONFIGURED USING THE FLAG SELECT
// DO NOT EDIT ANYTHING IN THIS SCRIPT DIRECTLY - YOUR FLAGS SHOULD BE CONFIGURED USING THE FLAG SELECT
//
//
@ -66,258 +66,249 @@ const software = {
foolfuuka : document . querySelector ( 'div[id="main"] article header .post_data' ) !== null
foolfuuka : document . querySelector ( 'div[id="main"] article header .post_data' ) !== null
} ;
} ;
// This is kinda necessary but I don't know how much. Can I just wrap checking regions on startup or is the whole script required? I won't be testing that for now.
/ * * W r a p p e r a r o u n d O b j e c t . a s s i g n a n d d o c u m e n t . c r e a t e E l e m e n t
( async ( ) => {
* @ param { string } element - The HTML Element to create .
* @ param { object } source - The properties to assign to the element .
/ * * W r a p p e r a r o u n d O b j e c t . a s s i g n a n d d o c u m e n t . c r e a t e E l e m e n t
* @ returns { object } The HTML tag created * /
* @ param { string } element - The HTML Element to create .
const createAndAssign = ( element , source ) => Object . assign ( document . createElement ( element ) , source ) ;
* @ param { Object } source - The properties to assign to the element .
* @ returns { object } The HTML tag created * /
const toggleFlagButton = state => document . getElementById ( 'append_flag_button' ) . disabled = state === 'off' ? true : false ;
const createAndAssign = ( element , source ) => Object . assign ( document . createElement ( element ) , source ) ;
/ * * A d d a s t y l e s h e e t t o t h e h e a d o f t h e d o c u m e n t .
/ * * A d d a s t y l e s h e e t t o t h e h e a d o f t h e d o c u m e n t .
* @ param { string } css - The CSS rules for the stylesheet .
* @ param { string } css - The CSS rules for the stylesheet .
* @ returns { object } The style element appended to the head * /
* @ returns { object } The style element appended to the head * /
const addGlobalStyle = css => document . head . appendChild ( createAndAssign ( 'style' , {
const addGlobalStyle = css => document . head . appendChild ( createAndAssign ( 'style' , {
type : 'text/css' ,
type : 'text/css' ,
innerHTML : css
innerHTML : css
} ) ) ;
/ * * W r i t e e x t r a i n f o r m a t i o n t o t h e c o n s o l e i f d e b u g M o d e i s s e t t o t r u e .
* @ param { string } text - The text to write to the console . * /
function debug ( text ) {
if ( debugMode ) {
console . log ( '[BantFlags] ' + text ) ;
}
}
/ * * W r a p p e r a r o u n d G M _ x m l h t t p R e q u e s t .
* @ param { string } method - The HTTP method ( GET , POST ) .
* @ param { string } url - The URL of the request .
* @ param { string } data - text for the form body .
* @ param { Function } func - The function run when we recieve a response . Response data is sent directly to it . * /
const makeRequest = ( ( method , url , data , func ) => {
GM . xmlHttpRequest ( {
method : method ,
url : url ,
data : data ,
headers : { "Content-Type" : 'application/x-www-form-urlencoded' } ,
onload : func
} ) ;
} ) ;
/** Itterate over selected flags are store them across browser sessions.*/
function saveFlags ( ) {
regions = [ ] ;
let selectedFlags = document . getElementsByClassName ( "bantflags_flag" ) ;
for ( var i = 0 ; i < selectedFlags . length ; i ++ ) {
regions [ i ] = selectedFlags [ i ] . title ;
}
GM . setValue ( namespace , regions ) ;
}
/ * * A d d a f l a g t o o u r s e l e c t i o n .
* @ param { string } flag - The flag to add to our selection . If no value is passed it takes the current value from the flagSelect . * /
function setFlag ( flag ) {
let UID = Math . random ( ) . toString ( 36 ) . substring ( 7 ) ;
let flagName = flag ? flag : document . querySelector ( '#flagSelect input' ) . value ;
let flagContainer = document . getElementById ( 'bantflags_container' ) ;
flagContainer . appendChild ( createAndAssign ( 'img' , {
title : flagName ,
src : back _end + flag _dir + flagName + '.png' ,
id : UID ,
className : 'bantflags_flag'
} ) ) ;
} ) ) ;
/ * * W r i t e e x t r a i n f o r m a t i o n t o t h e c o n s o l e i f d e b u g M o d e i s s e t t o t r u e .
if ( flagContainer . children . length >= max _flags ) {
* @ param { string } text - The text to write to the console . * /
toggleFlagButton ( 'off' ) ;
function debug ( text ) {
if ( debugMode ) {
console . log ( '[BantFlags] ' + text ) ;
}
}
}
/ * * W r a p p e r a r o u n d G M . x m l h t t p R e q u e s t .
document . getElementById ( UID ) . addEventListener ( "click" , ( e ) => {
* @ param { string } method - The HTTP method ( GET , POST ) .
flagContainer . removeChild ( e . target ) ;
* @ param { string } url - The URL of the request .
toggleFlagButton ( 'on' ) ;
* @ param { string } data - Data sent inn the form body .
saveFlags ( ) ;
* @ param { Function } func - The function run when we recieve a response . Response data is sent directly to it . * /
const MakeRequest = ( ( method , url , data , func ) => {
GM . xmlHttpRequest ( {
method : method ,
url : url ,
data : data ,
headers : { "Content-Type" : 'application/x-www-form-urlencoded' } ,
onload : func
} ) ;
} ) ;
} ) ;
/ * * T r y s o m e M a k e R e q u e s t a g a i n i f i t f a i l s .
if ( ! flag ) { // When we add a flag to our selection, save it for when we reload the page.
* @ param { function } func - The function to retry .
saveFlags ( ) ;
* @ param { XMLHttpRequest } resp - The XMLHttpResponse from the failed request . * /
function retry ( func , resp ) {
console . log ( '[BantFlags] Could not fetch flags, status: ' + resp . status ) ;
console . log ( resp . statusText ) ;
setTimeout ( func , requestRetryInterval ) ;
}
}
}
// TODO: this shouldn't be a object.
/** Create flag button and initialise our selected flags */
var nsetup = { // not anymore a clone of the original setup
function init ( ) {
namespace : 'BintFlegs' , // TODO: should be const.
let flagsForm = createAndAssign ( 'div' , {
flagsLoaded : false ,
className : 'flagsForm' ,
form : '<span id="bantflags_container"></span><button type="button" id="append_flag_button" title="Click to add selected flag to your flags. Click on flags to remove them. Saving happens automatically, you only need to refresh the pages that have an outdated flaglist on the page."><<</button><button id="flagLoad" type="button">Click to load flags.</button><div id="flagSelect" ><ul class="hide"></ul><input type="button" value="(You)" onclick=""></div>' ,
innerHTML : '<span id="bantflags_container"></span><button type="button" id="append_flag_button" title="Click to add selected flag to your flags. Click on flags to remove them. Saving happens automatically, you only need to refresh the pages that have an outdated flaglist on the page."><<</button><button id="flagLoad" type="button">Click to load flags.</button><div id="flagSelect" ><ul class="hide"></ul><input type="button" value="(You)" onclick=""></div>'
fillHtml : function ( ) { // TODO: this function should have a better name. Only called by nsetup.init, can be inlined?
} ) ;
MakeRequest (
"GET" ,
back _end + api _flags ,
"version=" + encodeURIComponent ( version ) ,
function ( resp ) {
debug ( 'Loading flags.' ) ;
if ( resp . status !== 200 ) {
retry ( nsetup . fillHtml , resp ) ;
return ;
}
let flagSelect = document . getElementById ( 'flagSelect' ) ;
let flagList = flagSelect . querySelector ( 'ul' ) ;
let flagInput = flagSelect . querySelector ( 'input' ) ;
let flags = resp . responseText . split ( '\n' ) ;
for ( var i = 0 ; i < flags . length ; i ++ ) {
let flag = flags [ i ] ;
flagList . appendChild ( createAndAssign ( 'li' , {
innerHTML : '<img src="' + back _end + flag _dir + flag + '.png" title="' + flag + '"> <span>' + flag + '</span>'
} ) ) ;
}
flagSelect . addEventListener ( 'click' , ( e ) => {
listItem = e . target . nodeName === 'LI' ? e . target : e . target . parentNode ;
if ( listItem . nodeName === 'LI' ) {
flagInput . value = listItem . querySelector ( 'span' ) . innerHTML ;
}
flagList . classList . toggle ( 'hide' ) ;
} ) ;
document . getElementById ( 'flagLoad' ) . style . display = 'none' ;
document . querySelector ( '.flagsForm' ) . style . marginRight = "200px" ;
flagSelect . style . display = 'inline-block' ;
nsetup . flagsLoaded = true ;
} ) ;
} ,
save : function ( ) {
let storedFlags = [ ] ;
let selectedFlags = document . getElementsByClassName ( "bantflags_flag" ) ;
for ( var i = 0 ; i < selectedFlags . length ; i ++ ) {
// Where do we append the flagsForm to?
storedFlags [ i ] = selectedFlags [ i ] . title ;
if ( software . yotsuba ) { document . getElementById ( 'delform' ) . appendChild ( flagsForm ) ; }
}
if ( software . nodegucaDoushio ) { document . querySelector ( 'section' ) . append ( flagsForm ) ; } // As posts are added the flagForm moves up the page. Could we append this after .section?
GM . setValue ( nsetup . namespace , storedFlags ) ;
for ( var i in regions ) {
regions = GM . getValue ( nsetup . namespace ) ;
setFlag ( regions [ i ] ) ;
} ,
}
setFlag : function ( flag ) {
let UID = Math . random ( ) . toString ( 36 ) . substring ( 7 ) ;
let flagName = flag ? flag : document . querySelector ( '#flagSelect input' ) . value ;
let flagContainer = document . getElementById ( 'bantflags_container' ) ;
flagContainer . appendChild ( createAndAssign ( 'img' , {
title : flagName ,
src : back _end + flag _dir + flagName + '.png' ,
id : UID ,
className : 'bantflags_flag'
} ) ) ;
if ( flagContainer . children . length >= max _flags ) {
nsetup . toggleFlagButton ( 'off' ) ;
}
document . getElementById ( UID ) . addEventListener ( "click" , ( e ) => {
document . getElementById ( 'append_flag_button' ) . addEventListener ( 'click' ,
flagContainer . removeChild ( e . target ) ;
( ) => flagsLoaded ? setFlag ( ) : alert ( 'Load flags before adding them.' ) ) ;
nsetup . toggleFlagButton ( 'on' ) ;
nsetup . save ( ) ;
document . getElementById ( 'flagLoad' ) . addEventListener ( 'click' , makeFlagSelect , { once : true } ) ;
} ) ;
}
if ( ! flag ) { // When we add a flag to our selection, save it for when we reload the page.
/** Get flag data from server and fill flags form. */
nsetup . save ( ) ;
function makeFlagSelect ( ) {
makeRequest (
"GET" ,
back _end + api _flags ,
"version=" + encodeURIComponent ( version ) ,
function ( resp ) {
debug ( 'Loading flags.' ) ;
if ( resp . status !== 200 ) {
return ;
}
}
} ,
init : function ( ) {
let flagsForm = createAndAssign ( 'div' , {
className : 'flagsForm' ,
innerHTML : nsetup . form
} ) ;
// Where do we append the flagsForm to?
let flagSelect = document . getElementById ( 'flagSelect' ) ;
if ( software . yotsuba ) { document . getElementById ( 'delform' ) . appendChild ( flagsForm ) ; }
let flagList = flagSelect . querySelector ( 'ul' ) ;
if ( software . nodegucaDoushio ) { document . querySelector ( 'section' ) . append ( flagsForm ) ; } // As posts are added the flagForm moves up the page. Could we append this after .section?
let flagInput = flagSelect . querySelector ( 'input' ) ;
let flags = resp . responseText . split ( '\n' ) ;
for ( var i in regions ) {
for ( var i = 0 ; i < flags . length ; i ++ ) {
nsetup . setFlag ( regions [ i ] ) ;
let flag = flags [ i ] ;
flagList . appendChild ( createAndAssign ( 'li' , {
innerHTML : '<img src="' + back _end + flag _dir + flag + '.png" title="' + flag + '"> <span>' + flag + '</span>'
} ) ) ;
}
}
document . getElementById ( 'append_flag_button' ) . addEventListener ( 'click' ,
flagSelect . addEventListener ( 'click' , ( e ) => {
( ) => nsetup . flagsLoaded ? nsetup . setFlag ( ) : alert ( 'Load flags before adding them.' ) ) ;
listItem = e . target . nodeName === 'LI' ? e . target : e . target . parentNode ; // So we can click the flag image and still select the flag.
if ( listItem . nodeName === 'LI' ) {
flagInput . value = listItem . querySelector ( 'span' ) . innerHTML ;
}
flagList . classList . toggle ( 'hide' ) ;
} ) ;
document . getElementById ( 'flagLoad' ) . addEventListener ( 'click' , nsetup . fillHtml , { once : true } ) ;
document . getElementById ( 'flagLoad' ) . style . display = 'none' ;
} ,
document . querySelector ( '.flagsForm' ) . style . marginRight = "200px" ; // Element has position: absolute and is ~200px long.
toggleFlagButton : state => document . getElementById ( 'append_flag_button' ) . disabled = state === 'off' ? true : false
flagSelect . style . display = 'inline-block' ;
} ;
flagsLoaded = true ;
} ) ;
}
/ * * S e l e c t a l l o f t h e p o s t n u m b e r s o n t h e p a g e .
/ * * a d d a l l o f t h h e p o s t n u m b e r s o n t h e p a g e t o p o s t N r s .
* @ param { string } selector - The CSS selector of the post numbers . * /
* @ param { string } selector - The CSS selector who ' s id is the post number . * /
function getPosts ( selector ) {
function getPosts ( selector ) {
let posts = document . querySelectorAll ( selector ) ;
let posts = document . querySelectorAll ( selector ) ;
for ( var i = 0 ; i < posts . length ; i ++ ) {
for ( var i = 0 ; i < posts . length ; i ++ ) {
let postNumber = software . yotsuba
let postNumber = software . yotsuba
? posts [ i ] . id . replace ( 'pc' , '' ) // Fuck you 4chan.
? posts [ i ] . id . replace ( 'pc' , '' ) // Fuck you 4chan.
: posts [ i ] . id ;
: posts [ i ] . id ;
postNrs . push ( postNumber ) ;
postNrs . push ( postNumber ) ;
}
debug ( postNrs ) ;
}
}
debug ( postNrs ) ;
}
/ * * T a k e t h e r e s p o n s e f r o m r e s o l v e R e f F l a g s a n d a p p e n d f l a g s t o t h e i r r e s p e c t i v e p o s t n u m b e r s .
/ * * T a k e t h e r e s p o n s e f r o m r e s o l v e R e f F l a g s a n d a p p e n d f l a g s t o t h e i r r e s p e c t i v e p o s t n u m b e r s .
* @ param { XMLHttpRequest } response - The response data from resolveRefFlags . * /
* @ param { XMLHttpRequest } response - The response data from resolveRefFlags . * /
function onFlagsLoad ( response ) {
function loadFlags ( response ) {
debug ( 'JSON: ' + response . responseText ) ;
debug ( 'JSON: ' + response . responseText ) ;
var jsonData = JSON . parse ( response . responseText ) ;
var jsonData = JSON . parse ( response . responseText ) ;
Object . keys ( jsonData ) . forEach ( function ( post ) {
Object . keys ( jsonData ) . forEach ( function ( post ) {
// Get the post header with a CSS selector. Different for each board software.
// Get the post header with a CSS selector. Different for each board software.
var flagContainer ;
var flagContainer ;
if ( software . nodegucaDoushio ) { flagContainer = document . querySelector ( '[id="' + post + '"] header' ) ; }
if ( software . nodegucaDoushio ) { flagContainer = document . querySelector ( '[id="' + post + '"] header' ) ; }
if ( software . yotsuba ) { flagContainer = document . querySelector ( '[id="pc' + post + '"] .postInfo .nameBlock' ) ; }
if ( software . yotsuba ) { flagContainer = document . querySelector ( '[id="pc' + post + '"] .postInfo .nameBlock' ) ; }
if ( software . foolfuuka ) { flagContainer = document . querySelector ( '[id="' + post + '"] .post_data .post_type' ) ; }
if ( software . foolfuuka ) { flagContainer = document . querySelector ( '[id="' + post + '"] .post_data .post_type' ) ; }
let flags = jsonData [ post ] ;
let flags = jsonData [ post ] ;
if ( flags . length > 0 ) {
if ( flags . length > 0 ) {
console . log ( '[BantFlags] Resolving flags for >>' + post ) ;
console . log ( '[BantFlags] Resolving flags for >>' + post ) ;
for ( var i = 0 ; i < flags . length ; i ++ ) {
for ( var i = 0 ; i < flags . length ; i ++ ) {
let flag = flags [ i ] ;
let flag = flags [ i ] ;
let newFlag = createAndAssign ( 'a' , {
let newFlag = createAndAssign ( 'a' , {
innerHTML : '<img src="' + back _end + flag _dir + flag + '.png" title="' + flag + '"> ' ,
innerHTML : '<img src="' + back _end + flag _dir + flag + '.png" title="' + flag + '"> ' ,
className : 'bantFlag' ,
className : 'bantFlag' ,
target : '_blank'
target : '_blank'
} ) ;
} ) ;
if ( software . foolfuuka ) {
if ( software . foolfuuka ) {
newFlag . style = 'padding: 0px 0px 0px ' + ( 3 + 2 * ( i > 0 ) ) + 'px; vertical-align:;display: inline-block; width: 16px; height: 11px; position: relative;' ;
newFlag . style = 'padding: 0px 0px 0px ' + ( 3 + 2 * ( i > 0 ) ) + 'px; vertical-align:;display: inline-block; width: 16px; height: 11px; position: relative;' ;
}
}
if ( software . nodegucaDoushio ) {
if ( software . nodegucaDoushio ) {
newFlag . title = flag ;
newFlag . title = flag ;
}
}
flagContainer . append ( newFlag ) ;
flagContainer . append ( newFlag ) ;
console . log ( '\t -> ' + flag ) ;
console . log ( '\t -> ' + flag ) ;
}
}
}
} ) ;
}
} ) ;
postNrs = [ ] ;
postNrs = [ ] ;
}
}
/** Get flags from the database using values in postNrs and pass the response on to onFlagsLoad */
/** Get flags from the database using values in postNrs and pass the response on to onFlagsLoad */
function resolveRefFlags ( ) {
function resolveFlags ( ) {
debug ( 'Board is: ' + board _id ) ;
debug ( 'Board is: ' + board _id ) ;
MakeRequest (
makeRequest (
'POST' ,
'POST' ,
back _end + api _get ,
back _end + api _get ,
'post_nrs=' + encodeURIComponent ( postNrs ) + '&board=' + encodeURIComponent ( board _id ) + '&version=' + encodeURIComponent ( version ) ,
'post_nrs=' + encodeURIComponent ( postNrs ) + '&board=' + encodeURIComponent ( board _id ) + '&version=' + encodeURIComponent ( version ) ,
function ( resp ) {
function ( resp ) {
if ( resp . status !== 200 ) {
if ( resp . status !== 200 ) {
retry ( resolveRefFlags , resp ) ;
console . log ( '[bantflags] Couldn\'t load flags. Refresh the page.' ) ;
return ;
return ;
}
onFlagsLoad ( resp ) ;
}
}
) ;
loadFlags ( resp ) ;
}
}
) ;
}
// This one await is what stops regular bantflags from working with GM4 lole.
( async ( ) => { // This one await is why we need a seperate script ;_;
regions = await GM . getValue ( n setup. n amespace) ;
regions = await GM . getValue ( n amespace) ;
if ( ! regions ) { // No flags set .
if ( ! regions ) { // Should only be called before you set flags for the first time .
regions = [ ] ;
regions = [ ] ;
window . confirm ( '[BantFlags]: No Flags detected. ') ;
window . confirm ( '[BantFlags]: No Flags detected. \nIf this is your first time running bantflags, look for the "Click to load flags." button at the bottom right of the thread, then select your flag and press the ">>" button. ') ;
}
}
// See Docs/styles.css
// See Docs/styles.css
addGlobalStyle ( '.flagsForm{float: right; clear: right; margin: 20px 10px;} #flagSelect{display:none;} .bantflags_flag{padding: 1px;} [title^="Romania"]{ position: relative; animation: shakeAnim 0.1s linear infinite;} @keyframes shakeAnim{ 0% {left: 1px;} 25% {top: 2px;} 50% {left: 1px;} 75% {left: 0px;} 100% {left: 2px;}} #flagSelect ul {list-style-type: none;padding: 0;margin-bottom: 0;cursor: pointer;bottom: 100%;height: 200px;overflow: auto;position: absolute;width:200px;background-color:#fff}#flagSelect ul li {display: block;}#flagSelect ul li:hover {background-color: #ddd;}#flagSelect {position: absolute;}#flagSelect input {width: 200px;} #flagSelect .hide {display: none;}#flagSelect img {margin-left: 2px;}' ) ;
addGlobalStyle ( '.flagsForm{float: right; clear: right; margin: 20px 10px;} #flagSelect{display:none;} .bantflags_flag{padding: 1px;} [title^="Romania"]{ position: relative; animation: shakeAnim 0.1s linear infinite;} @keyframes shakeAnim{ 0% {left: 1px;} 25% {top: 2px;} 50% {left: 1px;} 75% {left: 0px;} 100% {left: 2px;}} #flagSelect ul {list-style-type: none;padding: 0;margin-bottom: 0;cursor: pointer;bottom: 100%;height: 200px;overflow: auto;position: absolute;width:200px;background-color:#fff}#flagSelect ul li {display: block;}#flagSelect ul li:hover {background-color: #ddd;}#flagSelect {position: absolute;}#flagSelect input {width: 200px;} #flagSelect .hide {display: none;}#flagSelect img {margin-left: 2px;}' ) ;
// Flags need to be parsed differently and have different styles depending on board software .
// We get flags using different selectors, and we need to align them differently .
if ( software . yotsuba ) {
if ( software . yotsuba ) {
debug ( '4chan' ) ;
debug ( '4chan' ) ;
board _id = 'bant' ;
board _id = 'bant' ;
getPosts ( '.postContainer' ) ;
getPosts ( '.postContainer' ) ;
addGlobalStyle ( '.bantFlag {padding: 0px 0px 0px 5px; vertical-align:;display: inline-block; width: 16px; height: 11px; position: relative;} .flag{top: 0px !important;left: -1px !important}' ) ;
addGlobalStyle ( '.bantFlag {padding: 0px 0px 0px 5px; vertical-align:;display: inline-block; width: 16px; height: 11px; position: relative;} .flag{top: 0px !important;left: -1px !important}' ) ;
init ( ) ;
}
}
if ( software . nodegucaDoushio ) {
if ( software . nodegucaDoushio ) {
debug ( 'Nineball' ) ;
debug ( 'Nineball' ) ;
board _id = window . location . pathname . split ( '/' ) [ 1 ] ; // 'nap' or 'srsbsn'
board _id = window . location . pathname . split ( '/' ) [ 1 ] ;
getPosts ( 'section[id], article[id]' ) ;
getPosts ( 'section[id], article[id]' ) ;
addGlobalStyle ( '.bantFlag {cursor: default} .bantFlag img {pointer-events: none;}' ) ;
addGlobalStyle ( '.bantFlag {cursor: default} .bantFlag img {pointer-events: none;}' ) ;
init ( ) ;
}
}
if ( software . foolfuuka ) {
if ( software . foolfuuka ) {
@ -328,94 +319,90 @@ const software = {
addGlobalStyle ( '.bantFlag{top: -2px !important;left: -1px !important}' ) ;
addGlobalStyle ( '.bantFlag{top: -2px !important;left: -1px !important}' ) ;
}
}
resolveRefFlags ( ) ;
resolveFlags ( ) ;
} ) ( ) ;
if ( software . yotsuba ) {
if ( software . yotsuba ) {
const GetEvDetail = e => e . detail || e . wrappedJSObject . detail ;
const GetEvDetail = e => e . detail || e . wrappedJSObject . detail ;
const postFlags = post _nr => M akeRequest(
const postFlags = post _nr => m akeRequest(
'POST' ,
'POST' ,
back _end + api _post ,
back _end + api _post ,
'post_nr=' + encodeURIComponent ( post _nr ) + '&board=' + encodeURIComponent ( board _id ) + '®ions=' + encodeURIComponent ( regions ) + '&version=' + encodeURIComponent ( version ) ,
'post_nr=' + encodeURIComponent ( post _nr ) + '&board=' + encodeURIComponent ( board _id ) + '®ions=' + encodeURIComponent ( regions ) + '&version=' + encodeURIComponent ( version ) ,
func = resp => debug ( resp . responseText ) ) ;
func = resp => debug ( resp . responseText ) ) ;
// Send flags to the backend when we makle a post. Top is 4chanX, bottom is native extension.
// Send flags to the backend when we makle a post. Top is 4chanX, bottom is native extension.
document . addEventListener ( 'QRPostSuccessful' , e => postFlags ( e . detail . postID ) , false ) ;
document . addEventListener ( 'QRPostSuccessful' , e => postFlags ( e . detail . postID ) , false ) ;
document . addEventListener ( '4chanQRPostSuccess' , e => postFlags ( GetEvDetail ( e ) . postId ) , false ) ;
document . addEventListener ( '4chanQRPostSuccess' , e => postFlags ( GetEvDetail ( e ) . postId ) , false ) ;
// I need to look at these.
// I need to look at these.
document . addEventListener ( 'ThreadUpdate' , function ( e ) {
document . addEventListener ( 'ThreadUpdate' , function ( e ) {
var evDetail = GetEvDetail ( e ) ;
var evDetail = GetEvDetail ( e ) ;
var evDetailClone = typeof cloneInto === 'function' ? cloneInto ( evDetail , unsafeWindow ) : evDetail ;
var evDetailClone = typeof cloneInto === 'function' ? cloneInto ( evDetail , unsafeWindow ) : evDetail ;
//ignore if 404 event
//ignore if 404 event
if ( evDetail [ 404 ] === true ) {
if ( evDetail [ 404 ] === true ) {
return ;
return ;
}
}
evDetailClone . newPosts . forEach ( function ( post _board _nr ) {
evDetailClone . newPosts . forEach ( function ( post _board _nr ) {
var post _nr = post _board _nr . split ( '.' ) [ 1 ] ;
var post _nr = post _board _nr . split ( '.' ) [ 1 ] ;
postNrs . push ( post _nr ) ;
postNrs . push ( post _nr ) ;
} ) ;
} ) ;
resolve Ref Flags( ) ;
resolve Flags( ) ;
} , false ) ;
} , false ) ;
document . addEventListener ( '4chanThreadUpdated' , function ( e ) {
document . addEventListener ( '4chanThreadUpdated' , function ( e ) {
var evDetail = GetEvDetail ( e ) ;
var evDetail = GetEvDetail ( e ) ;
let threadID = window . location . pathname . split ( '/' ) [ 3 ] ;
let threadID = window . location . pathname . split ( '/' ) [ 3 ] ;
let postsContainer = Array . prototype . slice . call ( document . getElementById ( 't' + threadID ) . childNodes ) ;
let postsContainer = Array . prototype . slice . call ( document . getElementById ( 't' + threadID ) . childNodes ) ;
let lastPosts = postsContainer . slice ( Math . max ( postsContainer . length - evDetail . count , 1 ) ) ; //get the last n elements (where n is evDetail.count)
let lastPosts = postsContainer . slice ( Math . max ( postsContainer . length - evDetail . count , 1 ) ) ; //get the last n elements (where n is evDetail.count)
lastPosts . forEach ( function ( post _container ) {
lastPosts . forEach ( function ( post _container ) {
var post _nr = post _container . id . replace ( 'pc' , '' ) ;
var post _nr = post _container . id . replace ( 'pc' , '' ) ;
postNrs . push ( post _nr ) ;
postNrs . push ( post _nr ) ;
} ) ;
} ) ;
resolveRefFlags ( ) ;
resolveFlags ( ) ;
} , false ) ;
} , false ) ;
}
nsetup . init ( ) ;
if ( software . nodegucaDoushio ) {
}
// This is poking at the mutations made on the page to figure out what happened and thus what actions to take.
// There is full support for nodeguca but I don't have a Doushio board I feel comfortable spamming to ensure it works properly there. There is at least partial support.
new MutationObserver ( function ( mutations ) {
mutations . forEach ( function ( mutation ) {
if ( mutation . addedNodes . length > 0 ) { // A post was added.
var firstAddedNode = mutation . addedNodes [ 0 ] . nodeName ;
// Enter a thread or change boards. Checks for when a post is added while in the index.
if ( mutation . target . nodeName === 'THREADS' && firstAddedNode !== 'HR' && firstAddedNode !== 'SECTION' ) {
board _id = window . location . pathname . split ( '/' ) [ 1 ] ;
setTimeout ( getPosts ( 'section[id], article[id]' ) , 2000 ) ;
resolveFlags ( ) ;
init ( ) ;
}
if ( software . nodegucaDoushio ) {
// You post.
nsetup . init ( ) ;
if ( firstAddedNode === 'HEADER' ) {
let data = 'post_nr=' + encodeURIComponent ( mutation . target . id ) + '&board=' + encodeURIComponent ( board _id ) + '®ions=' + encodeURIComponent ( regions ) + '&version=' + encodeURIComponent ( version ) ;
// This is poking at the mutations made on the page to figure out what happened and thus what actions to take.
makeRequest (
// There is full support for nodeguca but I don't have a Doushio board I feel comfortable spamming to ensure it works properly there. There is at least partial support.
'POST' ,
new MutationObserver ( function ( mutations ) {
back _end + api _post ,
mutations . forEach ( function ( mutation ) {
data ,
if ( mutation . addedNodes . length > 0 ) { // A post was added.
function ( ) {
var firstAddedNode = mutation . addedNodes [ 0 ] . nodeName ;
postNrs . push ( mutation . target . id ) ;
resolveFlags ( ) ;
// Enter a thread or change boards. Checks for when a post is added while in the index.
} ) ;
if ( mutation . target . nodeName === 'THREADS' && firstAddedNode !== 'HR' && firstAddedNode !== 'SECTION' ) {
board _id = window . location . pathname . split ( '/' ) [ 1 ] ;
setTimeout ( getPosts ( 'section[id], article[id]' ) , 2000 ) ;
resolveRefFlags ( ) ;
nsetup . init ( ) ;
}
// You post.
if ( firstAddedNode === 'HEADER' ) {
let data = 'post_nr=' + encodeURIComponent ( mutation . target . id ) + '&board=' + encodeURIComponent ( board _id ) + '®ions=' + encodeURIComponent ( regions ) + '&version=' + encodeURIComponent ( version ) ;
MakeRequest (
'POST' ,
back _end + api _post ,
data ,
function ( ) {
postNrs . push ( mutation . target . id ) ;
resolveRefFlags ( ) ;
} ) ;
}
// Someone else posts. Checks to see if you're hovering over a post.
if ( firstAddedNode === 'ARTICLE' && mutation . target . nodeName !== "BODY" && mutation . target . id !== 'hover_overlay' ) {
postNrs . push ( mutation . addedNodes [ 0 ] . id ) ;
setTimeout ( resolveRefFlags , 1500 ) ;
}
}
}
} ) ;
} ) . observe ( document . body , { childList : true , subtree : true } ) ;
// Someone else posts. Checks to see if you're hovering over a post.
}
if ( firstAddedNode === 'ARTICLE' && mutation . target . nodeName !== "BODY" && mutation . target . id !== 'hover_overlay' ) {
} ) ( ) ;
postNrs . push ( mutation . addedNodes [ 0 ] . id ) ;
setTimeout ( resolveFlags , 1500 ) ;
}
}
} ) ;
} ) . observe ( document . body , { childList : true , subtree : true } ) ;
}