From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

/////////////////////////////////////////////////////////////////////////////////////////

// Enables user to set permanent labels and color backgrounds to anonymous IP accounts //

/////////////////////////////////////////////////////////////////////////////////////////



importStylesheet('User:Kaniivel/IPLabeller.css');



// allow user to override colorCodes in common.js, make sure property '4' stays empty

if (!window.colorCodes) {

	var colorCodes = {

		1:"#FC8888",	// red

		2:"#ffe299",	// yellow

		3:"#99FF33",	// green

		4:""			// white (must be empty)

	};

} else {

	colorCodes'4' = "";

}



var messages = {

	errNoStorage: 'No storage available. Seems that either:\n \

					a) your browser does not support local storage,\n \

					b) local storage is turned off, or\n \

					c) is full.',

	formAddLabel: 'add label',

	formChange  : 'change',

	formLabel   : 'Label',

	formColor   : 'Color',

	errMissingIP: 'Error: missing IP address!',

	lblDeleted  : 'Label removed!',

	lblMissing  : 'Missing label!',

	lblChanged  : 'Label changed!',

	lblAdded    : 'Label added!',

	errAction   : 'Error: unrecognized action!'			

}



preload([

    'https://upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Yes_check.svg/240px-Yes_check.svg.png',

    'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a2/X_mark.svg/210px-X_mark.svg.png',

    'https://upload.wikimedia.org/wikipedia/et/4/42/Ip_label_form_delete.png',

    'https://upload.wikimedia.org/wikipedia/et/3/38/Ip_label_form_submit.png'

]);



$(document).ready(function(){

	if( typeof(Storage) === "undefined" ) {

		// if there is no local storage available, display message and do nothing

		throw new Error( messages.errNoStorage );

	} else {

		// define two custom methods for storing objects

		Storage.prototype.setObject = function(key, value) {

			this.setItem(key, JSON.stringify(value));

		};

		Storage.prototype.getObject = function(key) {

			var value = this.getItem(key);

			return value && JSON.parse(value);

		};

		createLinks (false);

		createEvents ();

	}

});



$(document).mouseup(function (e) {

	var container = $("div.ip-label-popup");

	var link = $("a.mw-anonuserlink");

	if (!container.is(e.target) // if the target of the click isn't the container...

		&& container.has(e.target).length === 0) // ... nor a descendant of the container

	{

		container.hide();

		$(link).css({"font-weight": "normal"});

	}

	var fbcontainer = $("div.ip-label-feedback");

	if (!fbcontainer.is(e.target)

		&& fbcontainer.has(e.target).length === 0)

	{

		fbcontainer.hide();

	}	

});



function createLinks( refresh ) {

	var spacer = " ";

	

	if (refresh) {

		$("div.ip-label-container").remove();

		$("a.mw-anonuserlink").css("background-color","");

	}

	

	$("a.mw-anonuserlink").each(function() {

		// create link after every IP; add the IP into the link html code

		var ip = $(this).text();

		var linkText = messages.formAddLabel;

		

		var dataResult = getData( ip );

		var keyExists = dataResult.keyExists;

		var dataObj = dataResult.dataObj;

			

		if ( keyExists ) {

			if (dataObj.label) {

				linkText = dataObj.label;

			} else if (dataObj.color) {

				linkText = messages.formChange;

			}

			if (dataObj.color) {

				$(this).css("background-color", colorCodes dataObj.color ])

			}

		}

		var link = $("<div class='ip-label-container'></div>").html("<a href='#' class='ip-label-link' _ip='" + ip + "'>"+ linkText + "</a>");

		$(this).after(spacer, link);

	});

}



function createEvents () {

	$("a.ip-label-link").click(function(event) {

		// if the link was clicked ...

		event.preventDefault();

		

		var ip = $(this).attr("_ip");

		

		var dataResult = getData( ip );

		var keyExists = dataResult.keyExists;

		var dataObj = dataResult.dataObj;

				

		// ... make the IP address go bold ...

		var iplink = $(this).parent().prev();

		iplink.css({"font-weight": "bold"});



		// ... create div with input form ...

		$(this).after("<div class='ip-label-popup'>" + messages.formLabel + ": <form action='' class='ip-label-popup-form'><input type='hidden' name='ip_address' value='" + ip + "'><input type='text' name='label' autocomplete='off' size='60' value='"+ ( (keyExists && dataObj.label) ? dataObj.label : "") + "' maxlength='60' class='ip-label-popup-input'><div class='ip-label-popup-bottom'>" + messages.formColor + ":<input type='radio' name='color' value=1" + (keyExists && dataObj.color == 1 ? " checked" : "") + "><div class='ip-label-popup-bottom-red'></div><input type='radio' name='color' value=2" + (keyExists && dataObj.color == 2 ? " checked" : "") + "><div class='ip-label-popup-bottom-yellow'></div><input type='radio' name='color' value=3" + (keyExists && dataObj.color == 3 ? " checked" : "") + "><div class='ip-label-popup-bottom-green'></div><input type='radio' name='color' value=4" + (keyExists && dataObj.color == 4 ? " checked" : "") + "><div class='ip-label-popup-bottom-white'></div><div class='ip-label-submit-buttons'><div class='ip-label-form-delete'></div> <div class='ip-label-form-submit'></div></div></div></form></div>");

		

		// this is the div created in the previous statement 

		var popUpDiv = $(this).next();

		

		// set focus on input field

		$(popUpDiv).find("input.ip-label-popup-input").focus();

		

		// set up submit event for the form (we can have more than one way to submit the form) 

		$(popUpDiv).find("form.ip-label-popup-form").submit(function(event) {

			event.preventDefault();

			var data = $(this).serializeArray();

			var formObj = {};

			$.each(data, function(i, val) {

				formObjval.name = val.value;

			});

			// pass container div along with the object holding form data to the processor function  

			processForm(popUpDiv, formObj);

		});

		

		// set up click event for the form + button

		$(popUpDiv).find(".ip-label-form-submit").on("click", function(){

			var form = $(this).closest("form.ip-label-popup-form");

			var input = $("<input>").attr("type", "hidden").attr("name", "action").val("add");

			$(form).append($(input));

			$(form).submit();

			iplink.css({"font-weight": "normal"});

		});

		

		// set up click event for the form - button

		$(popUpDiv).find(".ip-label-form-delete").on("click", function(){

			var form = $(this).closest("form.ip-label-popup-form");

			var input = $("<input>").attr("type", "hidden").attr("name", "action").val("del");

			$(form).append($(input));

			$(form).submit();

			iplink.css({"font-weight": "normal"});

		});

	});

}



function processForm (popUpDiv, formObj) {

	var fb_msg, isOK;



	if ( !formObj.ip_address ) {

		// if somehow there is no IP address, call showError function

		showError( popUpDiv, messages.errMissingIP );

	}



	// the key for storage is IP address

	var ip = formObj.ip_address;



	// check if the key already exists in storage to set up flag for later use

	

	var dataResult = getData( ip );

	var keyExists = dataResult.keyExists;

			

	if ( formObj.action == "add" ) {

		if ( isBlank(formObj.label) && ( isEmpty(formObj.color) || formObj.color == 4 ) ) {

			// if ip label is empty or whitespace and color is undefined or white then delete the entry

			deleteData( ip );

			if (keyExists) {

				var fb_msg = messages.lblDeleted;

				var isOK = true;

			} else {

				var fb_msg = messages.lblMissing;

				var isOK = false;

			}

			showMessage (popUpDiv, fb_msg, isOK);

		} else {

			// the form has data to save

			if ( isEmpty (formObj.color) ) 

			{ 

				formObj.color = 4;

			}

			var newLabel = {

				label:$.trim(formObj.label),

				color:formObj.color

			};

			setData( ip, newLabel );

			if (keyExists) {

				var fb_msg = messages.lblChanged;

				var isOK = true;		

			} else {

				var fb_msg = messages.lblAdded;

				var isOK = true;

			}

			showMessage (popUpDiv, fb_msg, isOK);

		}

	} else if ( formObj.action == "del" ) {

		// delete was clicked, do delete

		deleteData ( ip );

		if (keyExists) {

			var fb_msg = messages.lblDeleted;

			var isOK = true;		

		} else {

			var fb_msg = messages.lblMissing;

			var isOK = false;

		}

		showMessage (popUpDiv, fb_msg, isOK);

	} else {

		showError( popUpDiv, messages.errAction );

	}



	popUpDiv.remove();

}



function showError (div, errormsg) {

	// show error message, destroy popup div and exit

	throw new Error( errormsg );

	$(div).remove();

}



function showMessage (div, fb_msg, isOK) {

	// show feedback message and hide/destroy popup divs

	// call refresh list function afterwards

	

	$(div).hide();

	

	var img_Y = 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Yes_check.svg/240px-Yes_check.svg.png';

	var img_X = 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a2/X_mark.svg/210px-X_mark.svg.png';

	

	// create div box for the message

	var msg_div = $("<div class='ip-label-feedback'><div class='ip-label-feedback-inner'><img src='" + (isOK ? img_Y : img_X) + "'><div class='ip-label-feedback-inner-message'>" + fb_msg + "</div></div></div>");

	

	$(div).after(msg_div);

	

	msg_div.delay( 1100 ).fadeOut( 1000, function(){

		msg_div.remove();

		$(div).remove();

		createLinks (true);

		createEvents ();

    });

}



function getData ( key ) {

	key = "lbl_" + key;

	var labelObj = localStorage.getObject( key );

	var keyExists = ( (typeof labelObj === undefined || labelObj === null) ? false : true );



	var dataObj;

	if (keyExists) {

		var dataObj = {

			label:labelObj.l,

			color:labelObj.c

		};

	}	

	return {

			keyExists: keyExists,

			dataObj: dataObj

	};  	

}



function deleteData ( key ) {

	key = "lbl_" + key;

	localStorage.removeItem( key );

}



function setData( key, dataObj ) {

	key = "lbl_" + key;

	var labelObject = { l: dataObj.label, c: dataObj.color };	

	localStorage.setObject(key, labelObject);

}



function isBlank (str) {

	return (!str || /^\s*$/.test(str));

}



function isEmpty(str) {

    return (!str || 0 === str.length);

}



function preload( arrayOfImages ) {

    $(arrayOfImages).each(function(){

        $('<img/>')[0].src = this;

    });

}