a cute full body pagedoll drawing of me a bald white feminine individual with heart shaped glasses and face tattoos cuddling a black and white longhaired cat
† Created on .

๐Ÿ›ธ๐Ÿ›ธFor You

A variety of fun/helpful things I've made. :-)

Code snippets

Graphics

Buttons

Icons


Code

Neocities edit current page button

Sunset Archive Shake Gift

Sunset Archive More by Same Author

Anniversary Widget on WidgetStar

Graphics

Buttons


Neocities Edit Current Page Button

An edit page button for your Neocities site. Embed this on any neocities site to create a link to edit the corresponding page in the Neocities text editor. Code:


function url_replace() {
        const path = window.location.pathname.replace(/\//g, '') ;
        let html = ".html"
        const base_url = 'https://neocities.org/site_files/text_editor?filename=' + path + html;
        
    document.querySelector('.editlink').innerHTML =
        `<a href="${base_url}">Edit Page</a>`;
        }
      url_replace();
</script></div>

Back to top?

Sunset Archive Tampermonkey Scripts

Shake Gift

Original code by nonethefewer. Edited for Sunset by me.


// @name        Sunset Archive: Shake Gift
// @author      nonethefewer original; agnes the alien
// @match       *://sunset.femslash.club/users/*/gifts
// @version     1.1.3.0
// @grant       none
// @description Shake gifts on Sunset Archive
// @license     MIT
// @icon        https://sunset.femslash.club/images/ao3_logos/logo_42.png
// @downloadURL for the original https://update.greasyfork.org/scripts/475546/AO3%3A%20Shake%20Gift.user.js
// @updateURL for the original https://update.greasyfork.org/scripts/475546/AO3%3A%20Shake%20Gift.meta.js
// ==/UserScript==
// 
// For use in Tampermonkey. Install and select the plus button from the dashboard, or create new script from the dropdown, paste this in.
(function($) {
    $(document).ready(function() {
        if ( !$('body').hasClass('logged-in') ) { return; }

        var $base_url = "https://sunset.femslash.club/collections/$COLLECTION$/works?commit=Sort+and+Filter&work_search%5Bquery%5D=id%3A$ID$";
        var $main = $( '#main' );
        var $thurl = "";
        $('.index.group li.work', $main).each( function() {
            var work_id = this.id.replace('work_', '');
            var collection = "";
            if ( work_id !== '' ) {
                var $dove = $('div.mystery', this);
                if ($dove.length > 0)
                {
                    collection = $('h5 a', this)[0].getAttribute("href").split("/")[2];
                    $thurl = $base_url.replace("$COLLECTION$", collection).replace("$ID$", work_id);
                    $('.actions', this).append('<a style="right: 0; position: absolute; margin-right: 10px;" href="' + $thurl + '">Shake Gift</a>');
                }
            }
        });
    });
})(window.jQuery);

Back to top?

More By Same Author

Adds extra links to the tags section at the top of an AO3 work page, redirecting user to any use of same tags by the same author. Original code by rallamajoop.

// @name			  sunset author+tags quick-search
// @version		  1.2
// @include		  https://sunset.femslash.club/works*
// @include		  https://sunset.femslash.club/chapters*
// @description Generates quick links from Sunset fics to more by the same author in the same fandom (or character/pairing/any other tag). Original code by rallamajoop
// @namespace   rallamajoop
// @downloadURL https://update.greasyfork.org/scripts/393481/AO3%20author%2Btags%20quick-search.user.js
// @updateURL https://update.greasyfork.org/scripts/393481/AO3%20author%2Btags%20quick-search.meta.js
// ==/UserScript==

/* Adds extra links to the tags section at the top of an AO3 work page, redirecting user to any use of same tags by the same author.
* ie. a quick way to find out if the writer of the great fic you just read has written anything else for the same fandom/pairing/trope/etc.

* If printCounts is set to 'true', code will also calculate and display the number of uses of each tag in the fandom/relationship/character sections.
* This will also make the links take longer to load, as code must pre-load each link individually. To limit load, I have not implemented this for freeform
* or other tags.

* Author-based search links are a bit of a hack, but most cases should now select correctly in the tags menu on the right. I've added a subheading identifing the tag to cover all bases.
*/

//Setting variables! Change these if you like
var printCounts = true; 		// setting this to false will prevent script for printing tag counts, which may decrease loading times and server load
var quickSearchText = "*"; 	// text for new links - change this if you want something other than an *. You can put <sup>TEXT</sup> to make it superscript
var autoSortResultsBy = ""; // valid options are "Kudos", "Word Count", "Date" or "" (none, usually defaults to date)
var importantTags = ["fandom","relationship","character"]; // these are the tags which the script prints counts for

//Proper code starts here
var loc = location.href;
var href="https://sunset.femslash.club/works?utf8=%E2%9C%93&commit=Sort+and+Filter&work_search"; //[relationship_names]=";
var workPage=["https://sunset.femslash.club/works/", "https:/sunset.femslash.club/chapters/"];
var scriptTag = "&greasemonkey"; //tag to flag that we've clicked an author quicktag link

var sortOpts = {"Kudos": "&work_search[sort_column]=kudos_count", "Word Count": "&work_search[sort_column]=word_count", "Date" : "&work_search[sort_column]=revised_at" };

if (isWorkPage(loc)) {
  // Story page, add extra links user-based search to each tag

  var h3=document.body.getElementsByClassName("byline heading");
  var authors=h3.item(0).getElementsByTagName('a');
  authors=parseAuthors(authors);

  var allTags=document.body.getElementsByClassName("work meta group").item(0);
  var dds = allTags.getElementsByTagName('dd');

  var links = dds.item(1).getElementsByTagName('a');

  for (var j=0; j<dds.length; j++) {
    var tags = dds.item(j);
    var tagType = getTagType(tags);
    if (!tagType) break;

    links = tags.getElementsByTagName('a');
    for (var i=links.length-1; i>=0; i--) {

      for (var a=0; a<authors.length; a++) {

        var author=authors[a];
        var tag = getTag(links.item(i).href);
        var newHref = buildSearch(tag, author, tagType);

        var isCreatedLink = tag.includes(links.item(i).href);
        var existing = document.querySelectorAll('[href="' + newHref + '"]');
        if (!isCreatedLink && existing.length==0) { //check that we aren't creating a duplicate link - can happen when page partially loads from cache

          var text = quickSearchText;
          var newlink=document.createElement('span');

          if (printCounts && printCountFor(tags) && !ignoreAuthor(author)) {
            //If this is an important tag, count search results
            var count = getNumFics(newHref);
            if (count>1) {
              text = "<b><sup>(" + count.toString() + ")<sup></b>";
            }
            else {
              text = "<sup>(1)<sup></b>";
            }
          }

          var toolTip = "'" + unformatTag(tag) + "' fic by " + author;
          newlink.innerHTML = " <a href=\"" + newHref + "\" title=\"" + toolTip + "\">" + text + "</a>";

          links.item(i).parentNode.appendChild(newlink);
        }
      }
    }
  }
}


else if (loc.includes(scriptTag)) {
  // Quicktags search results page, add title to show which tag is in use

  //var sTag = getBetween("work_search[relationship_names]=", loc, "&user_id=");
  let sTag, tagType;
  [tagType, sTag] = parseLoc(loc);
  var main = document.getElementById("main");
  var heading = main.getElementsByClassName("heading").item(0);

  sTag = unformatTag(sTag);

  var subTitle = "<br> Author QuickSearch: " + sTag;
  var span=document.createElement('h3');
  span.innerHTML = subTitle;

//  const sortBys = sortLinks(loc);
//  heading.parentNode.insertBefore(sortBys, heading.nextSibling); //not really necessary as of v1.2
  heading.parentNode.insertBefore(span, heading.nextSibling);

  checkTagBox(tagType, sTag);
}

//don't bother counting fics by orphan_account - these won't all be by same author anyway
function ignoreAuthor(author) {
  if (author == "orphan_account") return true;
  return false;
}

function getTagType(element) {
  var name = element.className;
  if (!name.includes(" tags")) return false;
  name = name.replace(" tags", "");
  return name;
}

//True if work or chapter
function isWorkPage(href) {
  for (var i=0; i<workPage.length; i++) {
    if (href.includes(workPage[i])) return true;
  }
  return false;
}

//Make sure tag is selected on the right menu
function checkTagBox(tagType, tag) {
  if (tagType == "warning") tagType = "archive_warning";
  debugger
/*  let btn = document.getElementById("toggle_include_" + tagType + "_tags");
  btn = btn.getElementsByTagName("button");
  btn = btn[0];
  if (btn.getAttribute("aria-expanded") == "false") {
    btn.click();
  }*/
  const par = document.getElementById("include_" + tagType + "_tags");
  const entries = par.getElementsByTagName("label");
  for (let i=0; i<entries.length; i++) {
    let entry = entries[i];
    if (entry.textContent.includes(tag)) {
      entry.getElementsByTagName("input")[0].checked=true;
      return;
    }
  }
}


//Generate links to sort by kudos etc
function sortLinks(urlStr) {
  var sortBys=document.createElement('div');

  let baseUrl = urlStr.replace(scriptTag, "");
  let keys = Object.keys(sortOpts);
  let inc = [true, true, true];
  for (var i =0; i<keys.length; i++) {
    let opt = sortOpts[keys[i]];
    if (baseUrl.includes(opt)) {
      baseUrl = baseUrl.replace(opt, "");
      inc[i] = false;
    }
  }

  for (var i =0; i < keys.length; i++) {
    if(inc[i]) {
      let link=document.createElement('a');
      let key=keys[i];
      link.href=baseUrl + sortOpts[key] + scriptTag;
      link.innerHTML = "Sort by " + key;
      sortBys.append("\u2003");
      sortBys.appendChild(link);
    }
  }

  return sortBys;
}

//Author+tag search address
function buildSearch(tag, author, tagType="relationship"){
	var href="https://sunset.femslash.club/works?utf8=%E2%9C%93&commit=Sort+and+Filter&work_search[" + tagType + "_names]="
  href+=tag + "&user_id=" + author;

  const sortBy = sortOpts[autoSortResultsBy];
  if (sortBy != undefined) href+= sortBy;

  href+=scriptTag;
  return href;
}

//Limit tag counts to fandom, relationship and character tags
function printCountFor(element) {
  var name = getTagType(element);
  for (var i=0; i<importantTags.length; i++) {
    if (importantTags[i] == name) return true;
  }
  return false;

}

//Retrieve page as javascript object
function getSourceAsDOM(url)
{
    var xmlhttp=new XMLHttpRequest();
    xmlhttp.open("GET",url,false);
    xmlhttp.send();
    var parser=new DOMParser();
    return parser.parseFromString(xmlhttp.responseText,"text/html");
}

//Counts results of author+tag search
function getNumFics(url) {
  var results = getSourceAsDOM(url);
  var works = results.getElementsByClassName("work index group")[0];

  if (works.children.length < 20) {
	  return works.children.length;
  }

  var h=results.getElementsByTagName("h2");
  if (h.length>0) {
    h=h[0];
	  var text = h.textContent;
    if (text.includes(" of ")) {
      text = getBetween(" of ", text, " Works");
      return text; //could convert this into an integer, but not much point
    }
  }
	return 20;
}

//May be multiple authors, may have pseudonyms. Returns as array
function parseAuthors(links) {
  var authors = [""];
  for (var i=0; i<links.length; i++) {
    var text = links.item(i).toString();
		authors[i] = getBetween("/users/", text, "/pseuds");
  }
  return authors;
}

//Retrieve tag and tag type from search string
function parseLoc(href) {
  const re=/.+&work_search\[(.+)_names\]=(.+)&user_id=.+/;
  const res = re.exec(href);
  if (res.length == 3) {
    return res.slice(1);
  }
  return ["",""];
}

//Format tag to pass to search
function getTag(href){
  var tag = getBetween("/tags/", href, "/works");
  tag = replaceAll(tag, "*s*","%2F");
  tag = replaceAll(tag, "*d*",".");
  tag = replaceAll(tag, "%20","+");
  return tag;
}

//Format tag from href for display in title
function unformatTag(tag) {
  tag = decodeURIComponent(tag);
  tag = replaceAll(tag, "*s*","/");
  tag = replaceAll(tag, "*a*","&");
  tag = replaceAll(tag, "*d*",".");
  tag = replaceAll(tag, "+", " ");
  return tag;
}


function getBetween(tag1, str, tag2) {
	var ret = str.split(tag1);
  if (ret.length<2) return "";
  ret=ret[1];
	ret = ret.split(tag2);
  if (ret.length<1) return "";
  ret = ret[0];
  return ret;
}

function replaceAll(str, search, replacement) {
	return str.split(search).join(replacement);
}



Back to top?

Anniversary WidgetStar Widget

Requires WidgetStar account.. Stupid simple.

LINK

Back to top?

Graphics

Buttons

Fandom Icon Archive

Click here for an archive of every 100x100px fandom/stock icon I've made.

Back to top?

pagedoll (c)
site button
[email protected]
Webrings and such!
Quaker Ring
Previous Next
| computer popup window graphic with a double venus symbol and it says femslash fans online |
MY femslash OTP is...
๐Ÿ’ž NAHLA X ANISHA ! ๐Ÿ’ž
previous random next


pinkring
prev | next
random | join
For The Dreamers

โ† Random? โ†’