/////////////////////////////////////////////////////////////////////////////////////////
// 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) {
formObj[val.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;
});
}