IP.Board Post Auto-Saving + Management

Save and manage post drafts for IP.Board forums.

// ==UserScript==
// @name	IP.Board Post Auto-Saving + Management
// @namespace	Makaze
// @include	*
// @grant	none
// @version	4.0.0
// @description Save and manage post drafts for IP.Board forums.
// ==/UserScript==

var GREEN_OPEN = 'http://i.minus.com/i3FmZuRl9edMv.png',
GREEN_CLOSED = 'http://i.minus.com/irSU8O8Tdghd9.png',
BLUE_OPEN = 'http://i.minus.com/iyk5uCne4V6fF.png',
BLUE_CLOSED = 'http://i.minus.com/i5qOrdsGxNJD.png',
CAPACITY = 5242880,
MakazeScriptStyles,
styleElem;

function dateAndTime() {
	var currentdate = new Date();
	var output = (((currentdate.getMonth() + 1) < 10) ? '0' + (currentdate.getMonth() + 1)  : (currentdate.getMonth() + 1)) + "/"
		+ ((currentdate.getDate() < 10) ? '0' + currentdate.getDate() : currentdate.getDate()) + "/"
		+ currentdate.getFullYear() + " @ "
		+ ((currentdate.getHours() < 10) ? '0' + currentdate.getHours() : currentdate.getHours()) + ":"
		+ ((currentdate.getMinutes() < 10) ? '0' + currentdate.getMinutes() : currentdate.getMinutes()) + ":"
		+ ((currentdate.getSeconds() < 10) ? '0' + currentdate.getSeconds() : currentdate.getSeconds());
	return output;
}

function roundToNthDecimal(d, n) {
	return Math.round(d * Math.pow(10, n)) / Math.pow(10, n);
}

function empty(elem) {
	while (elem.hasChildNodes()) {
		elem.removeChild(elem.lastChild);
	}
}

function createElement(type, callback) {
	var element = document.createElement(type);

	callback(element);

	return element;
}

function moveCaret(win, charCount) {
	var sel, range;
	if (win.getSelection) {
		sel = win.getSelection();
		if (sel.rangeCount > 0) {
			var textNode = sel.focusNode;
			var newOffset = sel.focusOffset + charCount;
			sel.collapse(textNode, Math.min(textNode.length, newOffset));
		}
	} else if ( (sel = win.document.selection) ) {
		if (sel.type != "Control") {
			range = sel.createRange();
			range.move("character", charCount);
			range.select();
		}
	}
}

function fade(elem, type, speed) {
	function defaultStyle(tag) {
		var defaultStyles = {},
		testElem = document.createElement(tag),
		getStyle = 'getComputedStyle' in window,
		styles;

		document.body.appendChild(testElem);

		styles = (getStyle) ? window.getComputedStyle(testElem) : testElem.currentStyle;

		for (var prop in styles) {
			defaultStyles[prop] = styles[prop];
		}

		document.body.removeChild(testElem);

		return defaultStyles;
	}

	var defaults = defaultStyle(elem.tagName),
	defaultOpacity,
	defaultDisplay,
	currentDisplay = (elem.style.display.length) ? elem.style.display : window.getComputedStyle(elem).display;

	if (elem.style.display.length) {
		elem.style.display = '';
	}

	defaultDisplay = (window.getComputedStyle(elem).display === 'none') ? defaults.display : window.getComputedStyle(elem).display;

	elem.style.display = currentDisplay;

	if (elem.style.display.length) {
		elem.style.opacity = '';
	}

	defaultOpacity = (window.getComputedStyle(elem).opacity === '0') ? defaults.opacity : window.getComputedStyle(elem).opacity;

	elem.style.opacity = 0;

	// Default values:

	switch (arguments.length) {
		case 1:
			type = 'toggle';
		case 2:
			speed = 300;
		break;
	}

	switch (type) {
		case 'in':
			elem.style.display = defaultDisplay;
			setTimeout(function() {
				elem.style.transition = 'all ' + speed + 'ms ease-in-out';
				elem.style.opacity = defaultOpacity;
				setTimeout(function() {
					elem.style.transition = '';
				}, speed + 10);
			}, 0);
		break;
		case 'out':
			elem.style.transition = 'none';
			elem.style.opacity = defaultOpacity;
			elem.style.transition = 'all ' + speed + 'ms ease-in-out';
			elem.style.opacity = 0;
			setTimeout(function() {
				elem.style.display = 'none';
				elem.style.transition = '';
				elem.style.opacity = '';
			}, speed + 10);
		break;
		case 'toggle':
		default:
			if (currentDisplay === 'none') {
				elem.style.display = defaultDisplay;
				setTimeout(function() {
					elem.style.transition = 'all ' + speed + 'ms ease-in-out';
					elem.style.opacity = defaultOpacity;
					setTimeout(function() {
						elem.style.transition = '';
					}, speed + 10);
				}, 0);
			} else {
				elem.style.transition = 'none';
				elem.style.opacity = defaultOpacity;
				elem.style.transition = 'all ' + speed + 'ms ease-in-out';
				elem.style.opacity = 0;
				setTimeout(function() {
					elem.style.display = 'none';
					elem.style.transition = '';
					elem.style.opacity = '';
				}, speed + 10);
			}
	}
}

// Classes constructor

function ClassHandler() {
	var self = this;

	this.classList = function(elem) {
		return elem.className.trim().split(/[\b\s]/);
	};

	this.hasClass = function(elem, className) {
		var classes = self.classList(elem),
		has = false,
		i = 0;

		for (i = 0; i < classes.length; i++) {
			if (classes[i] === className) {
				has = true;
				break;
			}
		}

		return (has);
	};

	this.addClass = function(elem, className) {
		var classes;

		if (!self.hasClass(elem, className)) {
			classes = self.classList(elem);
			classes.push(className);
			elem.className = classes.join(' ').trim();
		}

		return self;
	};

	this.removeClass = function(elem, className) {
		var classes = self.classList(elem),
		i = 0;

		for (i = 0; i < classes.length; i++) {
			if (classes[i] === className) {
				classes.splice(i, 1);
			}
		}

		elem.className = classes.join(' ').trim();

		return self;
	};

	this.toggleClass = function(elem, className) {
		var classes;

		if (self.hasClass(elem, className)) {
			self.removeClass(elem, className);
		} else {
			classes = self.classList(elem);
			classes.push(className);
			elem.className = classes.join(' ').trim();
		}

		return self;
	};
}

// Initilize

var Classes = new ClassHandler();

// End Classes constructor

// Event constructor

function EventHandler() {
	var events = [],
	matchedEvents = [],
	selector = document,
	self = this;

	this.selector = function(toSelect) {
		selector = toSelect;
		return self;
	};

	this.add = function(types, namespace, listener, useCapture) {
		var type,
		event,
		i = 0;

		types = types.split(/[\b\s]/);

		events.push({'selector': selector, 'namespace': namespace, 'types': types, 'listener': listener, 'useCapture': useCapture});
		event = events[events.length - 1];

		for (i = 0; i < event.types.length; i++) {
			type = event.types[i];
			selector.addEventListener(type, listener, useCapture);
		}

		return self;
	};

	this.remove = function(types, namespace, listener, useCapture) {
		var event,
		eventType,
		eventTypes,
		type,
		i = 0,
		j = 0,
		k = 0;

		if (!arguments.length) {
			if (matchedEvents.length) {
				for (i = 0; i < matchedEvents.length; i++) {
					event = matchedEvents[i];
					for (j = 0; j < event.types.length; j++) {
						type = event.types[j];
						event.selector.removeEventListener(type, event.listener, event.useCapture);
					}
				}
			} else {
				self.getEventsBySelector(selector).remove();
			}
		} else {
			types = types.split(/[\b\s]/);

			for (i = 0; i < events.length; i++) {
				event = events[i];
				if (event.selector == selector && event.namespace === namespace && event.useCapture === useCapture && event.listener === listener) {
					eventTypes = event.types;
					for (j = 0; j < eventTypes.length; j++) {
						eventType = eventTypes[j];
						for (k = 0; k < event.types.length; k++) {
							type = types[k];
							if (type === eventType) {
								selector.removeEventListener(type, event.listener, event.useCapture);
							}
						}
					}
					break;
				}
			}
		}

		matchedEvents = [];

		return self;
	};

	this.output = function() {
		if (!matchedEvents.length) {
			self.getAllEvents().output();
		} else {
			var output = matchedEvents;
			matchedEvents = [];
			return output;
		}
	};

	this.getAllEvents = function() {
		matchedEvents = events;
		return self;
	};

	this.getEventsBySelector = function(getSelector) {
		var event,
		i = 0;

		if (matchedEvents.length) {
			for (i = 0; i < matchedEvents.length; i++) {
				event = matchedEvents[i];
				if (event.selector != getSelector) {
					matchedEvents.splice(i, 1);
				}
			}
		} else {
			for (i = 0; i < events.length; i++) {
				event = events[i];
				if (event.selector == getSelector) {
					matchedEvents.push(event);
				}
			}
		}

		return self;
	};

	this.getEventsByType = function(types) {
		var eventTypes,
		eventType,
		event,
		type,
		hasType = false,
		i = 0,
		j = 0,
		k = 0;

		types = types.split(/[\b\s]/);

		if (matchedEvents.length) {
			for (i = 0; i < matchedEvents.length; i++) {
				event = matchedEvents[i];
				for (j = 0; j < eventTypes.length; j++) {
					eventType = eventTypes[j];
					for (k = 0; k < event.types.length; k++) {
						type = types[k];
						if (type === eventType) {
							hasType = true;
							break;
						}
					}
					if (hasType) {
						break;
					}
				}
				if (hasType) {
					matchedEvents.splice(i, 1);
				}
			}
		} else {
			for (i = 0; i < events.length; i++) {
				event = events[i];
				for (j = 0; j < eventTypes.length; j++) {
					eventType = eventTypes[j];
					for (k = 0; k < event.types.length; k++) {
						type = types[k];
						if (type === eventType) {
							hasType = true;
							break;
						}
					}
					if (hasType) {
						break;
					}
				}
				if (hasType) {
					matchedEvents.push(event);
				}
			}
		}
		
		return self;
	};

	this.getEventsByName = function(namespace) {
		var event,
		i = 0;

		if (matchedEvents.length) {
			for (i = 0; i < matchedEvents.length; i++) {
				event = matchedEvents[i];
				if (event.namespace !== namespace) {
					matchedEvents.splice(i, 1);
				}
			}
		} else {
			for (i = 0; i < events.length; i++) {
				event = events[i];
				if (event.namespace === namespace) {
					matchedEvents.push(event);
				}
			}
		}

		return self;
	};

	this.getEventsByListener = function(listener) {
		var event,
		i = 0;

		if (matchedEvents.length) {
			for (i = 0; i < matchedEvents.length; i++) {
				event = matchedEvents[i];
				if (event.listener !== listener) {
					matchedEvents.splice(i, 1);
				}
			}
		} else {
			for (i = 0; i < events.length; i++) {
				event = events[i];
				if (event.listener === listener) {
					matchedEvents.push(event);
				}
			}
		}

		return self;
	};
}

// Initialize

var Events = new EventHandler();

// End Event constructor

function refresh() {
	function createLogItem(source, i) {
		return createElement('div', function(log) {
			log.id = source[i].id;
			log.className = 'log-item';
			log.name = i;

			log.appendChild(createElement('div', function(header) {
				header.className = 'log-item-header';
				header.appendChild(createElement('a', function(link) {
					link.className = 'header-link';
					link.appendChild(createElement('img', function(icon) {
						icon.src = selectedIcon;
						icon.className = 'folderIcon';
					}));

					if (source[i].hasOwnProperty('name')) {
						link.appendChild(createElement('span', function(name) {
							name.className = 'name';
							name.appendChild(document.createTextNode(source[i].name));
						}));
						link.appendChild(document.createTextNode(' | '));
					}

					link.appendChild(document.createTextNode(source[i].date));
				}));

				header.appendChild(createElement('del', function(del) {
					del.className = 'delete';
					del.appendChild(document.createTextNode('Delete'));
				}));

				if (selected === 'defaultFolder') {
					header.appendChild(createElement('del', function(save) {
						save.className = 'save';
						save.appendChild(document.createTextNode('Move to Saved '));
						save.appendChild(createElement('img', function(icon) {
							icon.src = BLUE_OPEN;
							icon.className = 'folderIcon';
						}));
					}));
				} else {
					header.appendChild(createElement('del', function(rename) {
						rename.className = 'rename';
						rename.appendChild(document.createTextNode('Rename'));
					}));
				}

				header.appendChild(createElement('del', function(load) {
					load.className = 'load';
					load.appendChild(document.createTextNode('Load'));
				}));
			}));

			log.appendChild(createElement('div', function(msg) {
				msg.className = 'msg-content';
				msg.innerHTML = source[i].msg.replace(/\n/g, '<br />');
			}));
		});
	}

	var selected = document.getElementsByClassName('folderSelected')[0].title.toLowerCase() + 'Folder',
	source = (localStorage.getItem(selected)) ? JSON.parse(localStorage.getItem(selected)) : [],
	selectedIcon = (selected === 'defaultFolder') ? GREEN_CLOSED : BLUE_CLOSED,
	currentLength = 0,
	occupied,
	defaultFull,
	savedFull,
	queue = document.getElementById('SavedPostsMenu-queue'),
	capacity = document.getElementById('capacity'),
	capacityText = document.getElementById('capacity-text'),
	i = 0;

	document.getElementById('trash').getElementsByTagName('span')[0].childNodes[0].nodeValue = 0;

	empty(queue);

	if (source.length) {
		source.sort(function(a, b) {
			var dateA = new Date(a.date.replace(/@/g, '')),
			dateB = new Date(b.date.replace(/@/g, ''));
			return dateB - dateA;
		});

		for (i = 0; i < source.length; i++) {
			queue.appendChild(createLogItem(source, i));
		}
	} else {
		queue.appendChild(createElement('div', function(cont) {
			cont.appendChild(createElement('div', function(error) {
				error.className = 'error_notice';
				error.style.padding = '5px 0';
				error.appendChild(document.createTextNode('No messages to display.'));
			}));
		}));
	}

	if (!localStorage.length) {
		capacity.getElementsByTagName('div')[0].style.width = 0 + '%';
		capacityText.childNodes[0].nodeValue = 0 + '% full';
	} else {
		for (i = 0; i < localStorage.length; i++) {
			currentLength += localStorage.getItem(localStorage.key(i)).length;
		}
		occupied = (currentLength / CAPACITY) * 100;
		defaultFull = (localStorage.getItem('defaultFolder')) ? (localStorage.getItem('defaultFolder').length / CAPACITY) : 0;
		savedFull = (localStorage.getItem('savedFolder')) ? (localStorage.getItem('savedFolder').length / CAPACITY) + defaultFull : 0;
		document.getElementById('defaultFolder').style.width = defaultFull + '%';
		document.getElementById('savedFolder').style.width = savedFull + '%';
		occupied = roundToNthDecimal(occupied, 1);
		capacityText.childNodes[0].nodeValue = occupied + '% full';
		if (occupied >= 95 && !Classes.hasClass(capacity, 'full')) {
			Classes.addClass(capacity, 'full');
			Classes.addClass(capacityText, 'full');
		} else if (Classes.hasClass(capacity, 'full')) {
			Classes.removeClass(capacity, 'full');
			Classes.removeClass(capacityText, 'full');
		}
	}
}

function manageSavedPosts() {
	var alreadyExists = false,
	SavedPostsMenu,
	menu;

	// The menu

	if (document.getElementById('SavedPostsMenu') == null) {
		SavedPostsMenu = createElement('div', function(menu) {
			menu.id = 'SavedPostsMenu';
			menu.appendChild(createElement('div', function(padded) {
				padded.className = 'padded';
				padded.appendChild(createElement('div', function(close) {
					close.id = 'close-SavedPostsMenu';
					close.appendChild(createElement('span', function(span) {
						span.appendChild(document.createTextNode('x'));
					}));
				}));

				padded.appendChild(createElement('div', function(trash) {
					trash.id = 'trash';
					trash.appendChild(document.createTextNode('Empty Trash ('));
					trash.appendChild(createElement('span', function(span) {
						span.appendChild(document.createTextNode('0'));
					}));
					trash.appendChild(document.createTextNode(' Items)'));
				}));

				padded.appendChild(createElement('div', function(cap) {
					cap.id = 'capacity';
					cap.appendChild(createElement('div', function(folderCap) {
						folderCap.id = 'defaultFolder';
					}));

					cap.appendChild(createElement('div', function(folderCap) {
						folderCap.id = 'savedFolder';
					}));
				}));

				padded.appendChild(createElement('div', function(mass) {
					mass.id = 'mass-functions';
					mass.appendChild(createElement('span', function(cap_text) {
						cap_text.id = 'capacity-text';
						cap_text.appendChild(document.createTextNode('0% full'));
					}));

					mass.appendChild(createElement('a', function(refresh) {
						refresh.name = 'refresh';
						refresh.appendChild(document.createTextNode('Refresh'));
					}));
					mass.appendChild(document.createTextNode(' | '));
					mass.appendChild(createElement('a', function(toggle) {
						toggle.name = 'toggle-all';
						toggle.appendChild(document.createTextNode('Toggle All'));
					}));
					mass.appendChild(document.createTextNode(' | '));
					mass.appendChild(createElement('a', function(restore) {
						restore.name = 'restore-all';
						restore.appendChild(document.createTextNode('Restore All'));
					}));
					mass.appendChild(document.createTextNode(' | '));
					mass.appendChild(createElement('a', function(del) {
						del.name = 'delete-all';
						del.appendChild(document.createTextNode('Delete All'));
					}));
				}));

				padded.appendChild(createElement('div', function(select) {
					select.id = 'folderSelect';
					select.appendChild(createElement('img', function(icon) {
						icon.title = 'Default';
						icon.src = GREEN_OPEN;
						icon.className = 'folderSelected';
					}));

					select.appendChild(createElement('img', function(icon) {
						icon.title = 'Saved';
						icon.src = BLUE_CLOSED;
					}));
				}));

				padded.appendChild(createElement('div', function(folder) {
					folder.id = 'folderName';
					folder.appendChild(document.createTextNode('Default'));
				}));

				padded.appendChild(createElement('div', function(queue) {
					queue.id = 'SavedPostsMenu-queue';
				}));
			}));
		});

		document.body.appendChild(SavedPostsMenu);
	} else {
		alreadyExists = true;
	}

	menu = document.getElementById('SavedPostsMenu');

	refresh();

	// Kill the process if the menu already exists

	if (alreadyExists) {
		fade(menu, 'in');
		return false;
	}

	// Events

	// Handlers

	var closeHandler = function() {
		fade(menu, 'out');
	};

	var selectFolderHandler = function(event) {
		if (event.target.tagName !== 'IMG') {
			return false;
		}

		var folder = event.target.title,
		selected,
		folderName;

		if (Classes.hasClass(event.target, 'folderSelected')) {
			refresh();
			return false;
		}

		selected = document.getElementsByClassName('folderSelected')[0];
		folderName = document.getElementById('folderName');

		if (folder === 'Default') {
			event.target.src = GREEN_OPEN;
			selected.src = BLUE_CLOSED;
		} else {
			event.target.src = BLUE_OPEN;
			selected.src = GREEN_CLOSED;
		}

		Classes.removeClass(selected, 'folderSelected');
		Classes.addClass(event.target, 'folderSelected');
		Classes.toggleClass(folderName, 'savedFolderText');
		folderName.childNodes[0].nodeValue = folder;
		refresh();
	};

	var trashHandler = function() {
		var trash = document.getElementById('trash'),
		selected = document.getElementsByClassName('folderSelected')[0].title.toLowerCase() + 'Folder',
		selectedLog = JSON.parse(localStorage.getItem(selected)),
		logItems = document.getElementsByClassName('log-item'),
		thisLog,
		idToDelete,
		idToCompare,
		start,
		i = 0,
		messageNum;

		for (i = 0; i < logItems.length; i++) {
			thisLog = logItems[i];

			if (thisLog.hasAttribute('delete')) {
				idToDelete = thisLog.id;

				for (messageNum = 0; messageNum < selectedLog.length; messageNum++) {
					idToCompare = selectedLog[messageNum].id;
					if (idToCompare === idToDelete) {
						start = messageNum;
						break;
					}
				}

				selectedLog.splice(start, 1);
			}
		}

		trash.getElementsByTagName('span')[0].childNodes[0].nodeValue = 0;
		localStorage.setItem(selected, JSON.stringify(selectedLog));
	};

	var massHandler = function(event) {
		if (event.target.tagName !== 'A') {
			return false;
		}

		var logItems = document.getElementsByClassName('log-item'),
		trash = document.getElementById('trash'),
		thisLog,
		headers,
		i = 0;

		switch (event.target.name) {
			case 'refresh':
				refresh();
			break;
			case 'toggle-all':
				headers = document.getElementsByClassName('header-link');
				for (i = 0; i < headers.length; i++) {
					headers[i].click();
				}
			break;
			case 'restore-all':
				for (i = 0; i < logItems.length; i++) {
					thisLog = logItems[i];

					if (thisLog.hasAttribute('delete')) {
						thisLog.removeAttribute('delete');
						fade(thisLog, 'in', 100);
						trash.getElementsByTagName('span')[0].childNodes[0].nodeValue = parseInt(trash.getElementsByTagName('span')[0].childNodes[0].nodeValue) - 1;
					}
				}
			break;
			case 'delete-all':
				for (i = 0; i < logItems.length; i++) {
					thisLog = logItems[i];

					if (!thisLog.hasAttribute('delete')) {
						thisLog.getElementsByClassName('delete')[0].click();
					}
				}
			break;
		}
	};

	var selectMessageHandler = function(event) {
		if (!event.target.className || !Classes.hasClass(event.target, 'load')) {
			return false;
		}

		var toSelect = event.target.parentNode.nextSibling,
		idToLoad = toSelect.parentNode.id,
		msgToLoad,
		selected = document.getElementsByClassName('folderSelected')[0].title.toLowerCase() + 'Folder',
		selectedLog,
		idToCompare,
		iteration,
		range;

		if (document.selection) {
			range = document.body.createTextRange();
			range.moveToElementText(toSelect);
			range.select();
		} else if (window.getSelection()) {
			range = document.createRange();
			range.selectNode(toSelect);
			window.getSelection().removeAllRanges();
			window.getSelection().addRange(range);
		}

		// Nested click handler

		var loadMessageRichClickHandler = function(event) {
			var cursored = window.parent.document.getElementsByClassName('selectableForLoad'),
			thisCursored,
			i = 0,
			messageNum = 0;

			selectedLog = JSON.parse(localStorage.getItem(selected));

			for (messageNum = 0; messageNum < selectedLog.length; messageNum++) {
				idToCompare = selectedLog[messageNum].id;
				if (idToCompare === idToLoad) {
					iteration = messageNum;
					break;
				}
			}

			msgToLoad = selectedLog[iteration].msg;

			if (event.target.getElementsByTagName('body')[0].textContent.length) {
				event.target.getElementsByTagName('body')[0].innerHTML += msgToLoad;
			} else {
				event.target.getElementsByTagName('body')[0].innerHTML = msgToLoad;
			}

			for (i = 0; i < cursored.length; i++) {
				thisCursored = cursored[i];

				if (thisCursored.tagName === 'TEXTAREA') {
					thisCursored.style.cursor = '';
				} else {
					thisCursored.contentWindow.document.documentElement.style.cursor = '';
				}

				Classes.removeClass(thisCursored, 'selectableForLoad');
			}

			Events.getEventsByName('loadMessage').remove();

			fade(window.parent.document.getElementById('noticeBar'), 'out');
		};

		var loadMessageRichMouseoverHandler = function(event) {
			if (event.target.tagName !== 'IFRAME' || !event.target.title || !event.target.title.match('Rich text editor')) {
				return false;
			}

			event.target.contentWindow.document.documentElement.style.cursor = 'crosshair';

			Classes.addClass(event.target, 'selectableForLoad');
			Events.selector(event.target.contentWindow.document.documentElement).add('click', 'loadMessage', loadMessageRichClickHandler, false);

			Events.getEventsByName('loadMessageRich').remove();
		};

		var loadMessageClickHandler = function(event) {
			if (!event.target.className || !Classes.hasClass(event.target, 'cke_source')) {
				return false;
			}

			selectedLog = JSON.parse(localStorage.getItem(selected));

			var cursored = document.getElementsByClassName('selectableForLoad'),
			thisCursored,
			messageNum = 0,
			i = 0;

			for (messageNum = 0; messageNum < selectedLog.length; messageNum++) {
				idToCompare = selectedLog[messageNum].id;
				if (idToCompare === idToLoad) {
					iteration = messageNum;
					break;
				}
			}

			msgToLoad = selectedLog[iteration].msg;
			
			event.target.value += msgToLoad;

			for (i = 0; i < cursored.length; i++) {
				thisCursored = cursored[i];

				if (thisCursored.tagName === 'TEXTAREA') {
					thisCursored.style.cursor = '';
				} else {
					thisCursored.contentWindow.document.documentElement.style.cursor = '';
				}

				Classes.removeClass(thisCursored, 'selectableForLoad');
			}

			Events.getEventsByName('loadMessage').remove();

			fade(document.getElementById('noticeBar'), 'out');
		};

		var loadMessageMouseoverHandler = function(event) {
			if (!event.target.className || !Classes.hasClass(event.target, 'cke_source')) {
				return false;
			}

			event.target.style.cursor = 'crosshair';
			Classes.addClass(event.target, 'selectableForLoad');
		};

		Events.selector(document).add('mouseover', 'loadMessage', loadMessageMouseoverHandler, false);

		Events.selector(document).add('click', 'loadMessage', loadMessageClickHandler, false);

		Events.selector(document).add('mouseover', 'loadMessageRich', loadMessageRichMouseoverHandler, false);

		if (document.getElementById('noticeBar') == null) {
			document.body.appendChild(createElement('div', function(bar) {
				bar.id = 'noticeBar';
				bar.appendChild(document.createTextNode(''));
			}));
		}

		document.getElementById('noticeBar').childNodes[0].nodeValue = 'Click a post field to load this post.';

		fade(document.getElementById('noticeBar'), 'in');
	};

	var moveToSavedHandler = function(event) {
		if (!event.target.className || !Classes.hasClass(event.target, 'save')) {
			return false;
		}

		var defaultLog = JSON.parse(localStorage.getItem('defaultFolder')),
		savedLog = (localStorage.getItem('savedFolder')) ? JSON.parse(localStorage.getItem('savedFolder')) : [],
		msgToMove = event.target.parentNode.parentNode.id,
		msgToCompare,
		iteration,
		savedName,
		toHide = event.target.parentNode.parentNode;

		var moveAndRenameKeydownHandler = function(event) {
			var messageNum = 0;

			if (event.target.tagName === 'INPUT') {
				if (event.keyCode === 13) {
					savedName = event.target.value;
					for (messageNum = 0; messageNum < defaultLog.length; messageNum++) {
						msgToCompare = defaultLog[messageNum].id;
						if (msgToCompare === msgToMove) {
							iteration = messageNum;
							break;
						}
					}
					defaultLog[iteration].name = savedName;
					savedLog.push(defaultLog[iteration]);
					defaultLog.splice(iteration, 1);
					localStorage.setItem('defaultFolder', JSON.stringify(defaultLog));
					localStorage.setItem('savedFolder', JSON.stringify(savedLog));
					fade(toHide, 'out');
					fade(event.target.parentNode, 'out');
					Events.selector(document.getElementById('renameDialog')).remove('keydown', 'moveAndRenameKeydown', moveAndRenameKeydownHandler, false);
				}
			}
		};

		if (document.getElementById('renameDialog') == null) {
			document.body.appendChild(createElement('div', function(rename) {
				rename.id = 'renameDialog';
				rename.appendChild(document.createTextNode('Name this Message'));
				rename.appendChild(document.createElement('br'));
				rename.appendChild(createElement('inpty', function(input) {
					input.type = 'text';
					input.placeholder = 'Press enter to submit';
				}));
			}));
		}

		document.getElementById('renameDialog').getElementsByTagName('input')[0].value = '';

		fade(document.getElementById('renameDialog'), 'in');

		Events.selector(document.getElementById('renameDialog')).add('keydown', 'moveAndRenameKeydown', moveAndRenameKeydownHandler, false);
	};

	var renameHandler = function(event) {
		if (!event.target.className || !Classes.hasClass(event.target, 'rename')) {
			return false;
		}

		var renaming = event.target.parentNode.parentNode.getElementsByClassName('name')[0],
		savedLog = JSON.parse(localStorage.getItem('savedFolder')),
		msgToRename = event.target.parentNode.parentNode.id,
		msgToCompare,
		iteration,
		newName;

		if (renaming.hasAttribute('contenteditable')) {
			renaming.removeAttribute('contenteditable');
			renaming.removeAttribute('style');
			return false;
		}

		renaming.setAttribute('contenteditable', 'true');
		renaming.setAttribute('style', 'outline: none; background-color: rgba(255, 255, 255, .7); padding: 3px; cursor: text;');
		renaming.focus();
		moveCaret(window, renaming.textContent.length);

		var renameKeydownHandler = function(event) {
			if (event.keyCode == 13) {
				event.target.removeAttribute('contenteditable');
				event.target.removeAttribute('style');
				newName = event.target.textContent;
				for (var messageNum = 0; messageNum < savedLog.length; messageNum++) {
					msgToCompare = savedLog[messageNum].id;
					if (msgToCompare === msgToRename) {
						iteration = messageNum;
						break;
					}
				}
				savedLog[iteration].name = newName;
				localStorage.setItem('savedFolder', JSON.stringify(savedLog));
				Events.selector(event.target).remove('keydown', 'renameKeydown', renameKeydownHandler, false);
			}
		};

		Events.selector(renaming).add('keydown', 'renameKeydown', renameKeydownHandler, false);
	};

	var deleteHandler = function(event) {
		if (!event.target.className || !Classes.hasClass(event.target, 'delete')) {
			return false;
		}

		var parentLog = event.target.parentNode.parentNode;

		fade(parentLog, 'out', 100);
		parentLog.setAttribute('delete', '');
		document.getElementById('trash').getElementsByTagName('span')[0].childNodes[0].nodeValue = parseInt(document.getElementById('trash').getElementsByTagName('span')[0].childNodes[0].nodeValue) + 1;
	};

	var showMsgContentHandler = function(event) {
		if (!event.target.className || !(Classes.hasClass(event.target, 'header-link') || Classes.hasClass(event.target.parentNode, 'header-link'))) {
			return false;
		}

		var thisTarget = (Classes.hasClass(event.target, 'header-link')) ? event.target : event.target.parentNode,
		selected = document.getElementsByClassName('folderSelected')[0].title.toLowerCase() + 'Folder',
		folderIcon = thisTarget.getElementsByClassName('folderIcon')[0],
		parent = thisTarget.parentNode,
		selectedIcon,
		dels,
		i = 0;

		if (Classes.hasClass(folderIcon, 'isOpen')) {
			selectedIcon = (selected === 'defaultFolder') ? GREEN_CLOSED : BLUE_CLOSED;
		} else {
			selectedIcon = (selected === 'defaultFolder') ? GREEN_OPEN : BLUE_OPEN;
		}

		folderIcon.src = selectedIcon;
		Classes.toggleClass(folderIcon, 'isOpen');
		fade(parent.nextSibling, 'toggle', 100);
		for (i = 0, dels = parent.getElementsByTagName('del'); i < dels.length; i++) {
			fade(dels[i], 'toggle', 100);
		}
	};

	// Add events

	Events.selector(document.getElementById('close-SavedPostsMenu').getElementsByTagName('span')[0]).add('click', 'close', closeHandler, false);

	Events.selector(document.getElementById('folderSelect')).add('click', 'selectFolder', selectFolderHandler, false);

	Events.selector(document.getElementById('trash')).add('click', 'empty', trashHandler, false);

	Events.selector(document.getElementById('mass-functions')).add('click', 'mass', massHandler, false);

	Events.selector(menu).add('click', 'select', selectMessageHandler, false);

	Events.selector(menu).add('click', 'moveToSaved', moveToSavedHandler, false);

	Events.selector(menu).add('click', 'rename', renameHandler, false);

	Events.selector(menu).add('click', 'delete', deleteHandler, false);

	Events.selector(menu).add('click', 'showMsgContent', showMsgContentHandler, false);
}

if (document.getElementsByTagName('body')[0].id === 'ipboard_body') {
	// Styling

	if (document.getElementById('MakazeScriptStyles') == null) {
		MakazeScriptStyles = createElement('style', function(style) {
			style.id = 'MakazeScriptStyles';
			style.type = 'text/css';
		});
		document.head.appendChild(MakazeScriptStyles);
	}

	styleElem = document.getElementById('MakazeScriptStyles');

	if (styleElem.hasChildNodes()) {
		styleElem.childNodes[0].nodeValue += '\n\n';
	} else {
		styleElem.appendChild(document.createTextNode(''));
	}

	styleElem.childNodes[0].nodeValue += '#SavedPostsMenu { background-color: rgba(240, 240, 240, 0.8); width: 50%; height: 100%; position: fixed; z-index: 99999999; top: 0px; left: 25%; box-shadow: 0px 0px 3px #444; color: #222; overflow-y: auto; }  #SavedPostsMenu .padded { padding: 25px; }  #close-SavedPostsMenu { text-align: right; height: 0px; }  #close-SavedPostsMenu span { background-color: #222; color: #fff; font-size: 110%; display: inline-block; width: 25px; height: 25px; text-align: center; line-height: 25px; border-radius: 25px; opacity: 0.9; cursor: pointer; }  #trash { text-align: center; font-weight: bolder; background-color: rgba(250, 250, 245, 0.9); color: rgb(68, 68, 68); text-shadow: 0px 0px 2px rgb(170, 170, 170); box-shadow: 0px 0px 2px rgb(119, 119, 119); padding: 15px; margin: 0 100px; border-radius: 10px; font-size: 150%; margin-bottom: 15px; cursor: pointer; }  #mass-functions { text-align: right; text-shadow: 1px 1px rgb(255, 255, 255); font-weight: bolder; padding: 10px; font-style: oblique; background-color: rgba(255, 255, 255, .9); font-size: 120%; border-radius: 3px; margin-bottom: 10px; }  .log-item { margin: 5px 0; }  .log-item-header { margin: 10px 0; }  #SavedPostsMenu a, #SavedPostsMenu del, #SavedPostsMenu .undo, #SavedPostsMenu .error_notice { text-shadow: 1px 1px #FFF; font-weight: bolder; cursor: pointer; margin: 0 10px; }  #SavedPostsMenu del { text-decoration: none; float: right; display: none; }  .msg-content { background-color: rgba(255, 255, 255, .8); border-radius: 5px; box-shadow: 0px 0px 3px #777; padding: 15px; display: none; }  #SavedPostsMenu ol { list-style: decimal; padding-left: 40px; }  #SavedPostsMenu il { list-style: disc; padding-left: 40px; }  .log-item .undo { background-color: rgba(255, 255, 255, .7); font-style: oblique; margin: 0 7px; padding: 3px; border-radius: 3px; display: none; }  .log-item .error_notice { font-size: 120%; cursor: auto; }  #capacity { background-color: rgba(255, 255, 255, .7); border-radius: 3px; margin-bottom: 10px; overflow: hidden; }  #capacity > div { height: 10px; border-radius: 3px; -webkit-transition: all .2s ease-in-out; -moz-transition: all .2s ease-in-out; -o-transition: all .2s ease-in-out; transition: all .2s ease-in-out; }  #capacity > div#defaultFolder { background-color: #7f3; border-bottom: 1px solid #7C3; border-right: 1px solid #7C3; position: absolute; }  #capacity.full > div#savedFolder { background-color: #3cf; border-bottom: 1px solid #39C; border-right: 1px solid #39C; }  #capacity.full > div { background-color: #F11; border-bottom: 1px solid #C11; border-right: 1px solid #C11; }  #capacity-text { float: left; -webkit-transition: all .2s ease-in-out; -moz-transition: all .2s ease-in-out; -o-transition: all .2s ease-in-out; transition: all .2s ease-in-out; }  #capacity-text.full { color: #F11; text-shadow: 1px 1px #C11; }  .saved-notice-footer { float: left; background-color: rgba(255, 255, 255, 0.4) ! important; color: #676767 ! important; padding: 3px 5px ! important; border-radius: 5px; }  .last-saved { color: inherit ! important; }  .saved-warning { color: #F11 ! important; }  .saved-warning > strong { font-weight: bolder ! important; }  .open-SavedPostsMenu { text-decoration: underline ! important; cursor: pointer ! important; }  .open-SavedPostsMenu:hover { text-decoration: none ! important; }  #folderSelect { text-align: center; }  #folderSelect > img { height: 25px; cursor: pointer; padding: 5px; border: 1px dashed transparent; }  #folderSelect > img:not(:last-of-type) { margin-right: 5px; }  #SavedPostsMenu .folderSelected { padding: 5px; border-radius: 5px; border: 1px dashed #aaa ! important; }  #folderName { font-weight: bolder; padding-top: 5px; font-size: 130%; }  #SavedPostsMenu .savedFolderText { color: #3cf; text-shadow: 1px 1px #39C; }  #SavedPostsMenu img.folderIcon { height: 15px; }  #SavedPostsMenu .header-link > img.folderIcon { margin-right: 5px; }  #noticeBar { position: fixed; z-index: 9999999999; bottom: 0px; text-align: center; width: 100%; background-color: rgba(50, 50, 50, .9); color: #fff; box-shadow: 0px 0px 5px #111; font-size: 25px; font-weight: bolder; padding: 20px 0px; display: none; }  #renameDialog { position: fixed; z-index: 999999999; top: 50%; left: 50%; padding: 3px; height: 40px; width: 200px; margin-top: -24px; margin-left: -79px; background-color: #f8f8f8; border: 1px solid #ccc; border-radius: 5px; text-align: center; font-weight: bolder; display: none; }  #renameDialog > input { margin: 3px 0px; width: 95%; }';

	var autoSavePostHandler = function(event) {
		var editor,
		editorContainer,
		editorSubmitParent,
		editorContents,
		editorID,
		editorType,
		editor_bottom,
		footer;

		if (!event.target.tagName) {
			return false;
		}

		switch (event.target.tagName) {
			case 'TEXTAREA':
				if (event.target.hasAttribute('aria-label') && event.target.getAttribute('aria-label').match('Rich text editor')) {
					editor = event.target;
					editorContainer = event.target.parentNode.parentNode.parentNode.parentNode;
				} else {
					return false;
				}
			break;
			case 'IFRAME':
				if (event.target.title && event.target.title.match('Rich text editor')) {
					editor = event.target;
					editorContainer = event.target.parentNode.parentNode.parentNode.parentNode;
				} else {
					return false;
				}
			break;
			default:
				return false;
		}

		if (editorContainer.hasAttribute('auto-saving')) {
			return false;
		}

		editorContents = editorContainer.getElementsByClassName('cke_contents')[0];

		if (editorContents.id.match('editor')) {
			editorID = editorContents.id.split('editor_')[1];
			editorType = 'editor_';
		} else if (!editorContents.id.match('editor') && editorContents.id.match('edit')) {
			editorID = editorContents.id.split('edit-')[1];
			editorType = 'edit-';
		}

		editor_bottom = document.getElementById('cke_bottom_' + editorType + editorID);

		console.log('Saving from:', editor);

		footer = createElement('div', function(footer) {
			footer.className = 'saved-notice-footer';
			footer.appendChild(createElement('span', function(last_saved) {
				last_saved.className = 'last-saved';
			}));

			footer.appendChild(document.createTextNode(' '));

			footer.appendChild(createElement('a', function(open_menu) {
				open_menu.className = 'open-SavedPostsMenu';
				open_menu.appendChild(document.createTextNode('{Menu}'));
			}));
		});

		editor_bottom.insertBefore(footer, editor_bottom.firstChild);

		var openMenuHandler = function() {
			manageSavedPosts();
		};

		Events.selector(editor_bottom.getElementsByClassName('open-SavedPostsMenu')[0]).add('click', 'open_menu', openMenuHandler, false);

		function fireInterval(elemID, context) {
			var timeStamp = dateAndTime(),
			elem,
			saveState,
			elems,
			newEntry,
			i = 0;

			if (context.getElementsByTagName('textarea')[0] != null) {
				for (i = 0, elems = context.getElementsByTagName('textarea'); i < elems.length; i++) {
					if (elems[i].getAttribute('aria-label').match(elemID)) {
						elem = elems[i];
						if (!elem.value.length) {
							return false;
						}

						saveState = elem.value;
					}
				}
			} else {
				for (i = 0, elems = context.getElementsByTagName('iframe'); i < elems.length; i++) {
					if (elems[i].title.match(elemID)) {
						elem = elems[i];
						if (!elem.contentWindow.document.body.textContent.length) {
							return false;
						}

						saveState = elem.contentWindow.document.body.innerHTML;
					}
				}
			}

			newEntry = { 'id': elemID, 'date': timeStamp, 'msg': saveState };

			// The meat
			
			var defaultLog = (localStorage.getItem('defaultFolder')) ? JSON.parse(localStorage.getItem('defaultFolder')) : [],
			lastSavedElem = document.getElementById('cke_bottom_' + editorType + editorID).getElementsByClassName('last-saved')[0],
			newMessage = true,
			messageID,
			messageToEdit,
			currentLength = 0,
			entryLength,
			occupied,
			difference,
			normalSave = false,
			messageNum = 0,
			savedWarning,
			warningClass,
			warningText,
			kill = false;

			if (defaultLog.length) {
				for (messageNum = 0; messageNum < defaultLog.length; messageNum++) {
					messageID = defaultLog[messageNum].id;
					if (messageID === elemID) {
						newMessage = false;
						messageToEdit = messageNum;
						break;
					}
				}
			}

			if (!newMessage && saveState === defaultLog[messageToEdit].msg) {
				return false;
			}

			// Begin capacity check

			if (localStorage.length) {
				for (i = 0; i < localStorage.length; i++) {
					currentLength += localStorage.getItem(localStorage.key(i)).length;
				}
			}

			entryLength = JSON.stringify(newEntry).length;
			occupied = roundToNthDecimal((currentLength / CAPACITY) * 100, 1);

			if (newMessage) {
				if (((currentLength + entryLength) / CAPACITY) * 100 >= 95) {
					if (currentLength + entryLength > CAPACITY) {
						warningClass = 'over-capacity';
						warningText = ' Capacity reached. Delete old messages to continue saving.';
						kill = true;
					} else if (currentLength + entryLength === CAPACITY) {
						warningClass = 'full';
						warningText = ' Capacity reached. Delete old messages to continue saving.';
					} else {
						warningClass = 'full';
						warningText = ' ' + roundToNthDecimal(((currentLength + entryLength) / CAPACITY) * 100, 1) + '% full.';
					}
				} else {
					normalSave = true;
				}
			} else {
				difference = entryLength - JSON.stringify(defaultLog[messageToEdit]).length;

				if (((currentLength + difference) / CAPACITY) * 100 >= 95) {
					if (currentLength + difference > CAPACITY) {
						warningClass = 'over-capacity';
						warningText = ' Capacity reached. Delete old messages to continue saving.';
						kill = true;
					} else if (currentLength + difference === CAPACITY) {
						warningClass = 'full';
						warningText = ' Capacity reached. Delete old messages to continue saving.';
					} else {
						warningClass = 'full';
						warningText = ' ' + roundToNthDecimal(((currentLength + difference) / CAPACITY) * 100, 1) + '% full.';
					}
				} else {
					normalSave = true;
				}
			}

			// End capacity check

			empty(lastSavedElem);

			if (normalSave) {
				lastSavedElem.appendChild(document.createTextNode('Last saved: ' + timeStamp));
			} else {
				savedWarning = createElement('span', function(warning) {
					warning.className = 'saved-warning ' + warningClass;
					warning.appendChild(createElement('strong', function(type) {
						type.appendChild(document.createTextNode('Warning:'));
					}));

					warning.appendChild(document.createTextNode(warningText));
				});
				
				if (kill) {
					lastSavedElem.appendChild(savedWarning);
					return false;
				}

				lastSavedElem.appendChild(document.createTextNode('Last saved: ' + timeStamp + ' | '));
				lastSavedElem.appendChild(savedWarning);
			}

			if (newMessage) {
				defaultLog.push(newEntry);
			} else {
				defaultLog[messageToEdit].msg = saveState;
			}

			localStorage.setItem('defaultFolder', JSON.stringify(defaultLog));
		}

		var saveAtInterval = setInterval(function() {
			if (document.getElementById('cke_bottom_' + editorType + editorID) == null) {
				clearTimeout(saveAtInterval);
				return false;
			}
			fireInterval(editorID, editorContainer);
		}, 15000);

		editorContainer.setAttribute('auto-saving', '');

		editorSubmitParent = editor;

		while (editorSubmitParent.getElementsByClassName('input_submit')[0] == null && editorSubmitParent.parentNode) {
			editorSubmitParent = editorSubmitParent.parentNode;
		}

		var submitSavedPostHandler = function(event) {
			if (!event.target.className || event.target.className !== 'input-submit') {
				return false;
			}

			var defaultLog = JSON.parse(localStorage.getItem('defaultFolder')),
			messageID,
			messageNum  = 0;

			for (messageNum = 0; messageNum < defaultLog.length; messageNum++) {
				messageID = defaultLog[messageNum].id;
				if (messageID === editorID) {
					defaultLog.splice(messageNum, 1);
					localStorage.setItem('defaultFolder', JSON.stringify(defaultLog));
					break;
				}
			}
		};

		Events.selector(editorSubmitParent).add('click', 'submitSavedPost', submitSavedPostHandler, false);
	};

	Events.selector(document).add('mouseover', 'saveStart', autoSavePostHandler, false);
}