/**
* Extension for HtmlFactory
* @type {{newButtonSmall, newButtonTiny, newSelectUsers}}
*/
var HtmlFactoryExtension = (function() {
/**
* Creates a 'button' Html Element.
* The initial class attribute is <code>class='smallbutton'</code>.
* @param {function} [callback] - The callback function for the <code>onClick<code> event
* @param {string} [text] - The content text of the element (text shown on the button)
* @param {string} [id] - The value for the <code>id</code> attribute
* @returns {ElType} The 'button' HTML element
*/
var createButtonSmall = function(callback, text, id) {
return HtmlFactory.newButton('smallbutton', callback, text, id);
};
/**
* Creates a 'button' Html Element.
* The initial class attribute is <code>class='tinybutton'</code>.
* @param {function} [callback] - The callback function for the <code>onClick<code> event
* @param {string} [text] - The content text of the element (text shown on the button)
* @param {string} [id] - The value for the <code>id</code> attribute
* @returns {ElType} The 'button' HTML element
*/
var createButtonTiny = function ButtonTiny(callback, text, id) {
var elBtn = HtmlFactory.newButton('tinybutton', callback, text, id);
elBtn.style = 'margin:0;padding:0;width:auto;';
return elBtn;
};
/**
* Creates a 'Select' HTML element for selecting camamba users.
* The options will be generated by the list of users.
* The initial class attribute is <code>class='smallselect'</code>.
* @param {Object<string, User>[]} users - The list of users shown as options
* @param {string} [id] - The value for the <code>id</code> attribute
* @param {boolean} [isShowGivenNames] - <code>true</code> has options shown by the custom name if given instead of the camamba username
* @returns {ElType} The 'select' HTML element
*/
var createSelectUsers = function(users, id, isShowGivenNames) {
var elSelect = HtmlFactory.newSelect('smallselect', id);
var _onchangeCallback;
var _isShowGivenNames = (isShowGivenNames);
/**
* Returns the user of the selected option
* @returns {User} The current selected user
*/
elSelect.getSelectedUser = function() {
return elSelect.options[elSelect.selectedIndex].user;
};
/**
* Sets a callback function triggered by the events <code>OnChange</code>, <code>OnKeyUp</code> and <code>OnFocus</code>.
* Removes any former callback function registered to these events.
* @param {function} callback
*/
elSelect.setOnChangeKeyUpFocus = function(callback) {
if (_onchangeCallback) {
elSelect.removeEventListener("focus", _onchangeCallback);
elSelect.removeEventListener("change", _onchangeCallback);
elSelect.removeEventListener("keyup", _onchangeCallback);
}
if (typeof callback === 'function') {
_onchangeCallback = callback;
elSelect.addEventListener("focus", callback);
elSelect.addEventListener("change", callback);
elSelect.addEventListener("keyup", callback);
}
};
/**
* Recreates the options by the current list of users.
* @param {Object<string, User>[]} users - The list of users shown as options
*/
elSelect.updateUsers = function(users) {
var sortUsers = [];
var remainingUsers = {};
for (var i = 0; i <= elSelect.length - 1; i++) {
var userInSelect = elSelect[i].user;
if (!users[userInSelect.uid]) { // deleted users
elSelect.remove(i);
} else { // remaining users
remainingUsers[userInSelect.uid] = true;
sortUsers.push({ user:userInSelect, selected:elSelect[i].selected });
}
}
Object.keys(users).forEach(function(uid){
if (!remainingUsers[uid]) { // additional users
var user = users[uid];
sortUsers.push({ user:user, selected:false });
/**
* Html 'Option' Child of a Html 'Select' Element that holds a User
* @type {HTMLOptionElement}
* @property {User} user - The User related to the option
*/
elSelect.add(document.createElement('OPTION'));
}
});
elSelect.length = sortUsers.length;
var optionTextProp = _isShowGivenNames ? "name" : "uname";
sortUsers.sort(function (a, b) {
var nameA = a.user[optionTextProp].toLowerCase();
var nameB = b.user[optionTextProp].toLowerCase();
if (nameA < nameB) { return -1; }
if (nameA > nameB) { return 1; }
return 0;
});
sortUsers.forEach(function (opt, i) {
elSelect[i].text = opt.user[optionTextProp];
elSelect[i].value = opt.user.uid;
elSelect[i].user = opt.user;
elSelect[i].selected = opt.selected;
});
};
Object.defineProperties(elSelect, {
isShowGivenNames : {
get : function () { return _isShowGivenNames },
set : function (value) {
if (value != _isShowGivenNames) {
_isShowGivenNames = value;
elSelect.updateUsers();
}
}
}
});
elSelect.updateUsers(users);
return elSelect;
};
return {
newButtonSmall : createButtonSmall,
newButtonTiny : createButtonTiny,
newSelectUsers : createSelectUsers
}
})();
Object.keys(HtmlFactoryExtension).forEach(function (propName) {
HtmlFactory[propName] = HtmlFactoryExtension[propName];
});
/**
* Extension for Page
* @type {{ isGerman, route, localizeUri }}
*/
var PageExtension = (function() {
var isGerman = window.location.hostname.indexOf("de.camamba.com") >= 0;
var uriRoute = /^\/(.+?)(?:_de)?\.php.*/g.exec(location.pathname)[1];
/**
* Verifies an uri, if it loads the German version of camamba.
* @param {string} uri The uri for a camamba Page.
* @returns {boolean} <code>true</code> if the uri will request a camamba Page in German.
*/
var uriIsGerman = function(uri) {
return (uri.indexOf('www.de.camamba.com') >= 0);
};
/**
* Transforms the uri of a camamba Page wether to request that Page in English or German, depending the language of the current Page.
* @param {string} uri - The uri for a cammaba Page.
* @param {Object.<string,string>[]} [queryParamsObj] - A key-value Object for additional query parameter to be attached to the uri.
* @returns {string} The localized uri
*/
var uriLocalized = function(uri, queryParamsObj) {
var localizedUri = uri;
if (isGerman && !uriIsGerman(uri)) {
localizedUri = uri
.replace("www.camamba.com", "www.de.camamba.com")
.replace(".php", "_de.php");
} else if (!isGerman && uriIsGerman(uri)) {
localizedUri = uri
.replace("www.de.camamba.com", "www.camamba.com")
.replace("_de.php", "php");
}
var queryParams = '';
if (queryParamsObj) {
var hasParams = uri.indexOf('.php?') >= 1;
Object.keys(queryParamsObj).forEach(function (key) {
var sep = (hasParams ? '&' : '?');
var value = queryParamsObj[key];
queryParams += sep + key + '=' + value;
hasParams = true;
});
}
return localizedUri + queryParams;
};
return {
/**
* Indicates the localization of the current camamba Page.
* @returns {boolean} <code>true</code> if the current Page is in German
* <code>false</code> the current Page is in English
*/
isGerman : isGerman,
/**
* The current path in camamba according to the uri.
* @returns {string} The current path.
*/
route : uriRoute,
localizeUri : uriLocalized
};
})();
Object.keys(PageExtension).forEach(function (propName) {
Page[propName] = PageExtension[propName];
});
/**
* Represents a camamba user.
* Intitially tries to load the User from the database by the given uid.
* @constructor
* @param {string|number} uid Identifies the User with its camaba uid.
*/
function User(uid) {
var _uid = parseInt(uid, 10); // camamba user ID (readonly)
var _key = 'uid' + _uid, // key for storing (readonly)
_uname = "", // camamba username
_name = "", // custom username
_note = "", // custom annotation
_hasChanged = true; // is any value is unsaved (readonly)
/**
* @name User#uid
* @type number
* @readonly
*/
/**
* @name User#key
* @type String
* @readonly
*/
/**
* @name User#hasChanged
* @type Boolean
* @readonly
*/
/**
* @name User#note
* @type String
*/
Object.defineProperties(this, {
uid : { value : _uid, writable : false },
key : { value : _key, writable : false },
hasChanged : { get : function() { return _hasChanged; } },
uname : {
get : function() { return _uname; },
set : function(val) {
if (_uname != val) {
_uname = val;
_hasChanged = true;
}
}
},
name : {
get : function() { return _name || _uname || _uid.toString(); },
set : function(val) {
if (_name != val) {
_name = val;
_hasChanged = true;
}
}
},
note : {
get : function() { return _note; },
set : function(val) {
if (_note != val) {
_note = val;
_hasChanged = true;
}
}
}
});
/**
* Saves or updates the user in the database of this script.
* Overwrites an existing entry or creates a new entry if it doesn't alread exist.
*/
this.save = function() {
User.prototype.save.call(this);
_hasChanged = false;
};
/**
* Loads the User from the database of this script.
* @returns {Boolean} <code>true</code> if the user was found and could be sucessfully loaded from db
*/
this.load = function() {
var isSuccess = User.prototype.load.call(this);
if (isSuccess) {_hasChanged = false; }
return isSuccess;
};
/**
* Removes the User from the database of this script.
*/
this.remove = function () {
User.prototype.remove.call(this);
_hasChanged = true;
};
this.load();
}
User.prototype = {
constructor : User,
save : function() {
if (this.hasChanged) {
GM_setValue("uid" + this.uid, JSON.stringify({
uname : this.uname,
name : this.name,
note : this.note
}));
}
},
load : function() {
var isScuccess = false;
var loadedString = GM_getValue("uid" + this.uid);
if (loadedString) {
var loadedObj = JSON.parse(loadedString);
var uname = loadedObj.uname;
var name = loadedObj.name;
var note = loadedObj.note;
if (uname !== undefined && name !== undefined && note !== undefined){
this.uname = uname;
this.name = name;
this.note = note;
isScuccess = true;
}
}
return isScuccess;
},
remove : function() {
GM_deleteValue("uid" + this.uid);
},
/**
* Gets all users stored from the database determined for this Script.
* @returns {{}<string|number,User>[]} List with all Stored Users
*/
loadAllUsers : function() {
var users = {};
var storedKeys = GM_listValues();
for (var i = 0; i <= storedKeys.length - 1; i++) {
var key = storedKeys[i].toString();
if (key.indexOf('uid') === 0) {
var uid = key.substr(3);
users[uid] = new User(uid);
}
}
return users;
},
/**
* Has the browser open the profile Page of this user.
* @param {boolean} [asNewTab=false]
* <code>true</code>, Page is opened in a new tab.
* <code>false</code>, replaces the current Page.
*/
openProfilePage : function (asNewTab) {
var profPageLocPath = location.protocol + '//www.camamba.com/profile_view.php';
var queryParamsObj = { uid : this.uid, m : 'start' };
var uri = Page.localizeUri(profPageLocPath, queryParamsObj);
var target = asNewTab ? '_blank' : '_self';
window.open(uri, target);
}
};
/**
* Represents the veewards
* @type {{lol, drama, banHammer, cheese}}
*/
var veewards = (function () {
function Vee(idx, name) {
this.index = idx;
this.name = name;
}
/**
* This callback is displayed as part of the Requester class.
* @callback Vee~sendCallback
* @param {Date} timeSend - Time the veeward beeing send
*/
/**
* Tries to send a veeward.
* @param {User} [user] - The user to whom the veeward may be send
* @param {number} [coolDownPeriodSec] - Period in seconds for which no veeward will be send since last sent
* @param {Vee~sendCallback} [callback] - A function to be called when the veeward got tried to be send.
*/
Vee.prototype.send = function (user, coolDownPeriodSec, callback) {
if (!(user && user instanceof User)) { user = new User(602175); }
coolDownPeriodSec = parseInt(coolDownPeriodSec||0, 10);
if (typeof callback !== 'function') {
callback = function(now) {
console.debug(new Date(now * 1000), 'try to veeward ', user.name, ' with ', thisVee.name);
};
}
var now = function() {
var now = Date.now ? Date.now() : new Date().getTime();
return Math.floor(now / 1000);
}();
var lastVeeTime = GM_getValue('autoVeeTimestamp', 0);
if (lastVeeTime > now || lastVeeTime + coolDownPeriodSec < now) {
var thisVee = this, vhttp;
try {
vhttp = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
vhttp = new ActiveXObject('Microsoft.XMLHTTP');
} catch (E) {
vhttp = false;
}
}
if (!vhttp && typeof XMLHttpRequest != 'undefined') {
try {
vhttp = new XMLHttpRequest();
} catch (e) {
vhttp = false;
}
}
vhttp.open('POST', '/extras/setdata.php', true);
vhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
vhttp.onreadystatechange = function() {
GM_setValue('autoVeeTimestamp', now);
callback(now);
};
vhttp.send('sendvee=' + this.index + '&to=' + user.uid);
}
};
return {
lol: new Vee(1, 'LoL'),
drama: new Vee(2, 'Drama'),
banHammer: new Vee(3, 'Ban Hammer'),
cheese: new Vee(4, 'Cheese')
};
})();