Original My LotRO Configuration
I have finally reached the point where my lottery winners have become too much for My LotRO to handle. Granted, it took me a lot longer to get so many winning entries than some people who are lottery hogs, but I got there nonetheless. Eventually, you probably will, too.

Once you get lots of entries, your winning entries window on My LotRO gets all scrambled and its hard to tell which ones are recent, or if there even are any new ones. They start to get sorted randomly, so when you scroll to the bottom of the list, it's not necessarily the most recent winner.


GreaseMonkey Icon

*** UPDATE: Digero updated his thread a few hours after I posted this and has given instructions for both IE and Chrome users.*** There is a fix for this, however, if you are a Firefox user (and you should be!) Digero of Landroval posted his fix on the official forums back in June, and I will provide the steps for you here.

First, install the addon GreaseMonkey. This addon allows you to apply custom javascript to pages in your browser. You'll be prompted to restart Firefox, which you should do. Down in the bottom right corner of your browser will be the GreaseMonkey icon. You can left-click the icon to enable and disable all GreaseMonkey scripts.

Right-click on the icon and choose "New User Script..." and enter this information in the window that comes up:

Name: SortLottery
Namespace: my.lotro.com
Description: Sort the Lottery winnings by date, and filter out old winnings
Includes: http://my.lotro.com/*
* The asterisk is not a footnote, be sure to include it in the entry. This is a wildcard symbol, which means that ANY url starting with my.lotro.com will be included.

When you hit OK, Notepad should come up. If it doesn't, you'll be prompted to choose an application. Choose Notepad or a similar, simple text editor. When the text editor window opens, paste in the following code:

// ==UserScript==
// @name SortLottery
// @namespace my.lotro.com
// @description Sort the Lottery winnings by date, and filter out old winnings
// @include http://my.lotro.com/*
// ==/UserScript==



// *************************
// ***** User Settings *****
// *************************

// Any lottery winnings older than this many days will be hidden. Set to a
// very large number to always show all winnings.
var maxAgeDays = 7;

// Set to true to use the standard browser scroll bars instead of the custom
// My LotRO scroll bars (which don't support the mouse wheel).
var useBrowserScrollBars = false;



// ************************
// ***** Begin Script *****
// ************************
var now = new Date();
var today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
var minTime = today.getTime() - maxAgeDays * 24 * 60 * 60 * 1000;
var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

function LotteryEntry(row)
{
this.isValid = false;

var dateSpan = document.evaluate(".//span[@class='lotteryEndDate']", row, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (dateSpan == null)
return;

this.date = new Date(dateSpan.innerHTML);
this.dateText = dateSpan.innerHTML;

var serverNode = document.evaluate(".//span[@class='server']/strong", row, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (serverNode == null)
return;

var nameNode = document.evaluate("a", serverNode.parentNode.parentNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (nameNode == null)
return;

this.serverAndName = serverNode.innerHTML + "/" + nameNode.innerHTML;
this.server = serverNode.innerHTML;
this.name = nameNode.innerHTML;
this.nameHref = nameNode.getAttribute("href");

var lotteryText = document.evaluate("td/text()", row, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
this.lotteryName = "";
while (textNode = lotteryText.iterateNext())
{
this.lotteryName += textNode.nodeValue;
}
this.lotteryName = this.lotteryName.replace(/^\s*/, "").replace(/\s*$/, ""); // Trim whitespace

this.isValid = true;
}

function compareLotteryEntries(a, b)
{
// Put the ones closest to today first
var result = Math.abs(today.getTime() - a.date.getTime()) -
Math.abs(today.getTime() - b.date.getTime());

if (result == 0)
{
if (a.lotteryName < b.lotteryName)
result = -1;
else if (a.lotteryName > b.lotteryName)
result = 1;
}

if (result == 0)
{
if (a.serverAndName < b.serverAndName)
result = -1;
else if (a.serverAndName > b.serverAndName)
result = 1;
}

return result;
}

function newEntriesOnly(entry)
{
return entry.date.getTime() > minTime;
}

function oldEntriesOnly(entry)
{
return entry.date.getTime() <= minTime;
}

function addEntries(lotteryContainer, entries, entryFilter)
{
var hasDatesInPast = false;
for (var j = 0; j < entries.length; j++)
{
if (entries[j].date.getTime() != today.getTime())
{
hasDatesInPast = entries[j].date.getTime() < today.getTime();
break;
}
}

var lastLotteryName = null;
var lastLotteryTime = 0;
var charList = null;
var listWrapperInner = null;
var filtered = 0;
var lastCharTextNode = null;
var lastEntry = null;
for (var j = 0; j < entries.length; j++)
{
var e = entries[j];

if (entryFilter(e))
{
if (e.date.getTime() != lastLotteryTime)
{
var listWrapperOuter = document.createElement("tr");
listWrapperOuter.style.verticalAlign = "top";
lotteryContainer.appendChild(listWrapperOuter);

listWrapperInner = document.createElement("td");
listWrapperInner.className = "left right pad";
listWrapperOuter.appendChild(listWrapperInner);

var dateSpan = document.createElement("span");
dateSpan.className = "lotteryEndDate";
dateSpan.setAttribute("title", e.dateText);
if (e.date.getTime() == today.getTime())
{
dateSpan.style.color = "#FFFF00";
dateSpan.innerHTML = (hasDatesInPast ? "Ended" : "Ending") + " Today";
}
else if (Math.abs(e.date - today) <= 24 * 60 * 60 * 1000) // Yesterday or tomorrow
{
dateSpan.style.color = "#C2C242";
if (e.date < today)
dateSpan.innerHTML = "Ended Yesterday";
else
dateSpan.innerHTML = "Ending Tomorrow";
}
else if (Math.abs(e.date - today) < 7 * 24 * 60 * 60 * 1000) // Less than a week
{
if (e.date.getTime() < today.getTime())
dateSpan.innerHTML = "Ended " + (e.date.getDay() < today.getDay() ? "on " : "last ") + dayNames[e.date.getDay()];
else
dateSpan.innerHTML = "Ending " + (e.date.getDay() > today.getDay() ? "on " : "next ") + dayNames[e.date.getDay()];
}
else
{
if (e.date.getTime() < today.getTime())
dateSpan.innerHTML = "Ended on " + e.dateText;
else
dateSpan.innerHTML = "Ending on " + e.dateText;
}
listWrapperInner.appendChild(dateSpan);

lastLotteryTime = e.date.getTime();
lastLotteryName = null;
lastEntry = null;
}

if (e.lotteryName != lastLotteryName)
{
var titleDiv = document.createElement("div");
titleDiv.innerHTML = e.lotteryName;
titleDiv.setAttribute("title", e.lotteryName);
listWrapperInner.appendChild(titleDiv);

charList = document.createElement("div");
charList.style.paddingLeft = "10px";
charList.style.paddingBottom = "5px";
listWrapperInner.appendChild(charList);

lastLotteryName = e.lotteryName;
lastEntry = null;
}

if (lastEntry != null && lastEntry.serverAndName == e.serverAndName)
{
currentCharCount++;
lastCharTextNode.nodeValue = " (x" + currentCharCount + ") ";
}
else
{
var charItem = document.createElement("div");
var nameLink = document.createElement("a");
nameLink.setAttribute("href", e.nameHref);
nameLink.innerHTML = e.name;

var serverNode = document.createElement("span");
serverNode.style.color = "#858585";
serverNode.innerHTML = e.server;

charList.appendChild(charItem);
charItem.appendChild(nameLink);
charItem.appendChild(lastCharTextNode = document.createTextNode(" "));
charItem.appendChild(serverNode);

lastEntry = e;
currentCharCount = 1;
}
}
else
{
filtered++;
}
}

return filtered;
}

var lotteryTables = document.evaluate("//table[@id='lotterysignups']/tbody", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

for (var i = 0; i < lotteryTables.snapshotLength; i++)
{
var lotteryTableBody = lotteryTables.snapshotItem(i);
var entries = [];

var rows = document.evaluate("tr", lotteryTableBody, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

for (var j = 0; j < rows.snapshotLength; j++)
{
var row = rows.snapshotItem(j);
var entry = new LotteryEntry(row);
if (entry.isValid)
{
entries.push(entry);
lotteryTableBody.removeChild(row);
}
}

entries.sort(compareLotteryEntries);

var filtered = addEntries(lotteryTableBody, entries, newEntriesOnly);

if (filtered > 0)
{

var linkTr = document.createElement("tr");
lotteryTableBody.appendChild(linkTr);
linkTr.style.verticalAlign = "top";

var linkTd = document.createElement("td");
linkTr.appendChild(linkTd);
linkTd.className = "left right pad";

if (filtered == entries.length)
{
msgDiv = document.createElement("div");
msgDiv.innerHTML = "No winning entries in the past " + maxAgeDays + (maxAgeDays == 1 ? " day" : " days");
linkTd.appendChild(msgDiv);
}

var a = document.createElement("a");
linkTd.appendChild(a);
a.innerHTML = "Show all " + entries.length + " winning entries";
a.setAttribute("href", "javascript:null");
a.addEventListener("click",
(function(linkTr, lotteryTableBody, entries)
{
return function(evt)
{
lotteryTableBody.removeChild(linkTr);
addEntries(lotteryTableBody, entries, oldEntriesOnly);

// Refresh the jQuery scrollbars
if (!useBrowserScrollBars && typeof unsafeWindow.jQuery != 'undefined')
unsafeWindow.jQuery(".scroll-pane").jScrollPane( {showArrows:true, dragMinHeight:12, scrollbarWidth:15, scrollbarMargin:0} );

evt.preventDefault(); // "return false"
}
})(linkTr, lotteryTableBody, entries),
true);
}
}


if (useBrowserScrollBars)
{
var scrollPanes = document.evaluate("//div[@class='scroll-pane']", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 0; i < scrollPanes.snapshotLength; i++)
{
var pane = scrollPanes.snapshotItem(i);

pane.className = ""; // Prevents the jScrollPane script from finding this div
pane.style.overflowX = "hidden";
pane.style.overflowY = "scroll";
}
}
else if (typeof unsafeWindow.jQuery != 'undefined')
{
// Prevent the thumb from being less than 12px high
unsafeWindow.jQuery.fn.jScrollPane.defaults.dragMinHeight = 12;
}

GreaseMonkey Configuration
There are two settings at the very top that you can use to customize the script. Save the file (it will be named automatically) and refresh your My LotRO page to see the changes.

The Current Entries window now indicates when the lotteries will close. More importantly, the Winning Entries window is now sorted by most recently ended lottery, and will keep all your winning entries in order indefinitely.

Finally, if you want more info on the My LotRO Lotteries, check out Xy's guide on Mordor or Bust.