Jump to content
  • Automatically Updating Thread Tracker (Jcink)

       (0 reviews)

    Simply provide this tracker with a list of threads that you want to track, and it will automatically stay up to date and show you who posted last and whether it's your turn. Note that it will only show threads that the person viewing the list is allowed to see, so you can safely use this tracker to track faction threads in a public ooc area, for example. You can post this tracker multiple times in the same thread for different characters, or you can list all your character's threads in a single instance of the tracker.


    The settings for your character/site are all in the first <script></script> block, to configure the way it works or adjust it to work on a specific site/skin - you may need to edit those but you shouldn't need to touch anything else (if you're comfortable with css you can fiddle with those bits). Feel free to PM me if you can't get it working on your site.


    This uses the skin's default link and text colours, so it works on both light and dark themes. It will adjust to any screen width, and will work in jcink's default mobile mode as well.




    Thread List - This is where you tell it which threads to track by listing the thread IDs (eg if the url of the thread includes showtopic=73 or t=73 then the Thread ID is 73). You can have any number of sections in the tracker, each specified as "Section Name": [threadID, threadID, threadID], and the sections separated by commas inside the {}. You might like to organize your threads by character, or by event threads vs 1-on-1, or whatever works for you.  If any section name contains the words "On Hold" or "Closed", it will not include the last poster for that thread or flag whether it is your turn.


    Character Names - When not using the Previous Poster setting below, the tracker will assume that it is your turn if the last poster is not any of the characters in this list. If you leave this blank, it will use the name of the account you use to post this.


    Previous Poster - if your site does strict posting order, you can use the Thread ID and the name of the character who posts before you; the tracker will only show that it is your turn if the last poster in that thread is the one who specified here. If you leave this commented out, or for any threads not in this list, the tracker will show it is your turn any time you are not the last poster.


    Classes - for themes/skins not based on the jcink default theme, you will likely need to change some or all of these. If any of the sections of the tracker don't show up (It should show thread title, forum/location, thread description, last poster's name, and last post date), then right click on that element of the actual page/post, and click Inspect Element. Find the closest wrapping element with a class or an id, and change the appropriate line to that. For class names, include a period in front of the class name, if you are referencing an id, you will need to put "[id=whatever_it_is]" instead.


    For example:


    Here, the post date is wrapped in an <a> tag that does not have a class, but that is inside a <span> with class="ttPost_date", so  you would need to change const Post_Date_Class = ".postdetails"; to const Post_Date_Class = ".ttPost_Date";


    Note: for the forum/location, use the navigation bar's class or id rather than the <a> tag's if it has one, because the script is looking for the last link inside the specified element.

    Actual Template Responsive

    Tracker Code by FizzyElf

    Template code

    //*** CONFIGURATION ***//
    //List the ids of the threads you want tracked in each category. 
    //You can also add or remove categories. e.g. "New Category": [1, 3, 5],
    const Thread_List = {
        "Active Threads": [],
        "On Hold": [],
        "Closed": []
    //List your characters on the next line, e.g. ["Character One","Character Two"]
    //This is how the tracker knows whether you are the last poster
    const Character_Names = [];
    //To specify who posts immediately before you when using strict posting order, list 
    //the threadIDs and character names on the next line 
    //e.g. {12:"Character Name", 34: "Other Character"}
    const Previous_Poster = {};
    //if your template uses nonstandard class names these might need to be changed
    //if certain details of each thread don't appear in the tracker, use Inspect Element 
    //in your browser on those elements of the thread page or ask your skin creator
    const Character_Name_Class = ".normalname";
    const Post_Date_Class = ".postdetails";
    const Thread_Title_Class = ".topic-title";
    const Thread_Desc_Class = ".topic-desc";
    const Navigation_Class = "#navstrip";
    //if the icons don't show up, change this to false
    const Skin_Already_Uses_Fontawesome = true;
    const scriptelements = document.getElementsByTagName("script");
    const Current_Script = scriptelements[scriptelements.length - 1];
    const Is_Mobile = (document.getElementById("mobile") !== null);
    var filesadded = [];
    function loadJsFile(filename, callback) {
        if (!filesadded.includes(filename)) {
            var fileref = document.createElement('script')
            fileref.setAttribute("type", "text/javascript")
            fileref.setAttribute("src", filename)
            if (callback) {
                fileref.onreadystatechange = callback;
                fileref.onload = callback;
    (Skin_Already_Uses_Fontawesome && !Is_Mobile) || loadJsFile('https://kit.fontawesome.com/fccaf1af24.js');
    const startLoadCuratedTracker = async function () {
        if (Character_Names.length == 0) Character_Names.push($($(Character_Name_Class).last()).text());
        for (var section in Thread_List) {
            FillCuratedTracker(section, Thread_List[section]);
        async function FillCuratedTracker(sectionname, sectionlist) {
            const closed = /closed|on hold/i.test(sectionname);
            let thistracker;
            if (closed) thistracker = $("<div class='fizzhistorywrap'></div>");
            else thistracker = $("<div class='fizztrackerwrap'></div>");
            for (let threadID of sectionlist) {
                GetThreadDetails(threadID, closed, thistracker)
        async function GetThreadDetails(threadID, closed, thistracker) {
            let href = `/index.php?showtopic=${threadID}&view=getlastpost`;
            let data = '';
            try {
                console.log(`fetching ${href}`);
                data = await $.get(href);
            } catch (err) {
                console.log(`Ajax error loading page: ${href} - ${err.status} ${err.statusText}`);
            let doc = new DOMParser().parseFromString(data, 'text/html');
            const {title, location, threadDesc, lastPoster, postDate} = parseThread(doc);
            let myturn = '';
            if (Previous_Poster[threadID]) {
                myturn = (lastPoster.includes(Previous_Poster[threadID])) ? 'fa-arrow-alt-circle-right' : 'fa-check';
            } else {
                myturn = (Character_Names.some(function (k) { return ~k.indexOf(lastPoster); })) ? 'fa-check' : 'fa-arrow-alt-circle-right';
            var descSeparator = "";
            if (threadDesc) descSeparator = "|";
            if (closed) {
                thistracker.append($(`<div class="fizztracker-item"><b><a href="${href}">${title.trim()}</a></b><br>
        ${location} ${descSeparator} ${threadDesc}</div>`));
            } else {
                thistracker.append($(`<div class="fizztracker-item"><b><span class="status fas ${myturn}"></span><a 
        ${location} ${descSeparator} ${threadDesc} <br> Last Post: ${lastPoster} - ${postDate}</div>`));
            if (!thistracker.children()) {
                thistracker.append('<div class="fizztracker-item">None</div>');
        function parseThread(doc) {
            if ($("body#mobile", doc).length) {
                return parseMobile(doc);
            } else {
                return parseDesktop(doc);
        function parseMobile(doc) {
            const title = $(".maintitle", doc).last().text();
            const location = $($(".row2.touch-area", doc)[0]).text();
            let threadDesc = "";
            if (threadDesc.startsWith(",")) threadDesc = threadDesc.substring(1);
            const postAuthorDivs = $(".post-username", doc);
            const lastPoster = $(postAuthorDivs[postAuthorDivs.length - 1]).text().trim();
            const postDateDivs = $(".post-date", doc);
            let postDate = $(postDateDivs[postDateDivs.length - 1]).text();
            if (postDate.indexOf(",") > 0) {
                postDate = postDate.substring(0, postDate.indexOf(","));
            return {title, location, threadDesc, lastPoster, postDate};
        function parseDesktop(doc) {
            const title = $(Thread_Title_Class, doc).text();
            const location = $(`${Navigation_Class} a:last-of-type`).first().text();
            let threadDesc = $(Thread_Desc_Class, doc).text();
            if (threadDesc.startsWith(",")) threadDesc = threadDesc.substring(1);
            const postAuthorDivs = $(Character_Name_Class, doc);
            let lastPoster = $(postAuthorDivs[postAuthorDivs.length - 1]).text().trim();
            const postDateDivs = $(Post_Date_Class, doc);
            let postDate = $(postDateDivs[postDateDivs.length - 1]).text();
            if (postDate.indexOf(",") > 0) {
                postDate = postDate.substring(0, postDate.indexOf(","));
            if (postDate.indexOf(":") > 0) {
                postDate = postDate.substring(postDate.indexOf(":") + 1, postDate.length);
            return {title, location, threadDesc, lastPoster, postDate};
    if (window.jQuery) startLoadCuratedTracker();
    else loadJsFile('https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js', startLoadCuratedTracker);
    <span style="font-size: 90%;"><i aria-hidden="true" style="color: #fffd;text-shadow: 1px 1px 0 black, -1px -1px 0 black;" class="fas fa-paw"></i> Tracker Code <i aria-hidden="true" style="/*! color: whitesmoke; *//*! text-shadow: 1px 1px 0 black, -1px -1px 0 black; */display: none;" class="fas fa-code-branch"></i> by <a href="http://fizzyelf.jcink.net">FizzyElf </a> <i aria-hidden="true" style="color: #fffd;text-shadow: 1px 1px 0 black, -1px -1px 0 black;" class="fas fa-paw"></i></span>
    @import url("https://fonts.googleapis.com/css?family=Arvo");
    .fizztrackerwrap, .fizzhistorywrap { position: relative; max-width: 500px; margin: 10px auto; padding: 1px 15px;}
    .fizztrackerwrap p, .fizzhistorywrap p { position: relative;  font: 15px/1.1 arvo; border-bottom: 1px solid;padding: 0 0.75em;}
    .fizzthreadwrap {display: block; position: relative; text-decoration: none;}
    .fizztracker-item .fa-check {color: green;}
    .fizztracker-item .fa-arrow-alt-circle-right {color: brown;}
    .fizztracker-item { margin-left: 2em;}
    .fizztrackerwrap .fizztracker-item { text-indent: -1.5em;}
    .fizztracker-item .status { width: 1.5em; text-align: center;}

    User Feedback

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.


Search In
  • More options...
Find results that contain...
Find results in...
  • Create New...

Important Information

By using this site, you agree to our Terms of Use, Guidelines and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.