Greasy Fork

camamba-utils

utils for modifying the DOM and fetching info of a webpage of camamba

目前为 2016-06-30 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.cloud/scripts/20132/134453/camamba-utils.js

/**
 * Extension for HtmlFactory
 */
(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 _users = users, _isShowGivenNames = isShowGivenNames;
        var _onchangeCallback;
        /**
         * Recreates the options by the current list of users.
         */
        var updateOptions = function() {
            var sortUsers = [];
            var remainingUsers = {};
            for (var i = 0; i <= elSelect.length - 1; i++) {
                var userInSelect = elSelect[i].user;
                if (userInSelect) {
                    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;
            });
            // refresh select
            elSelect.value = elSelect.options[elSelect.selectedIndex].value;
        };
        /**
         * Returns the user of the selected option
         * @returns {User} The current selected user
         */
        var 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
         */
        var 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);
            }
        };
        Object.defineProperties(elSelect, {
            /**
             * list of users of type {{uid:User}}
             */
            users : {
                get : function() { return _users },
                set : function(value) {
                    _users = value;
                    updateOptions();
                }
            },
            /**
             * <code>true</code> shows the custom given names
             * <code>false</code> shows the camamba names
             */
            isShowGivenNames : {
                get : function() { return _isShowGivenNames },
                set : function(value) {
                    if (value != _isShowGivenNames) {
                        _isShowGivenNames = value;
                        updateOptions();
                    }
                }
            },
            refresh : { value : updateOptions },
            selectedUser : { value : getSelectedUser },
            setOnChangeKeyUpFocus : { value : setOnChangeKeyUpFocus }
        });
        updateOptions();
        return elSelect;
    };
    Object.defineProperties(HtmlFactory, {
        newButtonSmall : { value: createButtonSmall },
        newButtonTiny : { value: createButtonTiny },
        newSelectUsers : { value: createSelectUsers }
    });
})();

/**
 * Extension for Page
 */
(function() {
    var isGerman = window.location.hostname.indexOf("de.camamba.com") >= 0;
    var urlRoute = /^\/(.+?)(?:_de)?\.php.*/g.exec(location.pathname)[1];
    /**
     * Verifies an url, if it loads the German version of camamba.
     * @param {string} url The url for a camamba Page.
     * @returns {boolean} <code>true</code> if the url will request a camamba Page in German.
     */
    var urlIsGerman = function(url) {
        return (url.indexOf('www.de.camamba.com') >= 0);
    };
    /**
     * Transforms the url of a camamba Page wether to request that Page in English or German, depending the language of the current Page.
     * @param {string} uri - The url for a cammaba Page.
     * @param {Object.<string,string>[]} [queryParamsObj] - A key-value Object for additional query parameter to be attached to the url.
     * @returns {string} The localized url
     */
    var uriLocalized = function(uri, queryParamsObj) {
        var localizedUri = uri;
        if (isGerman && !urlIsGerman(uri)) {
            localizedUri = uri
                .replace("www.camamba.com", "www.de.camamba.com")
                .replace(".php", "_de.php");
        } else if (!isGerman && urlIsGerman(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;
    };
    Object.defineProperties(Page, {
        /**
         * Indicates the localization of the current camamba Page.
         */
        isGerman : { value: isGerman },
        /**
         * The current path in camamba according to the url.
         */
        route : { value: urlRoute },
        localizeUri : { value: uriLocalized }
    });
})();


/**
 * 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); // camamba user ID (readonly)
    var _key = 'uid' + _uid; // key for storing (readonly)
    var _hasChanged = true;
    var backingFields = {
        uname : "", name : "", note : "",
        age : Number.NaN, gender : "",
        isPremium : false, isReal : false, isSuper : false,
        location : {}, distanceInKm : Number.NaN, gps : "", place : "",
        online : {}, isOnlineNow : false, lastSeen : new Date("invalid"),
        room : {}, roomId : "", roomName : "",
        lastUpdated : Date.now(), lastChanged : Date.now()
    };
    var setField = function(fieldName, val) {
        _lastUpdated = Date.now();
        if (backingFields[fieldName] !== val) {
            backingFields[fieldName] = val;
            _lastChanged = _lastUpdated;
            _hasChanged = true;
        }
    };
    var getField = function(fieldName) { return backingFields[fieldName]; };

    Object.defineProperties(getField("location"), {
        distanceInKm : {
            get: function() { return getField('distanceInKm'); },
            set: function(val) { setField("distanceInKm", val); }
        },
        gps : {
            get: function() { return getField("gps"); },
            set: function(val) { setField("gps", val); }
        },
        place : {
            get: function() { return getField("place"); },
            set: function(val) { setField("place", val); }
        }
    });
    Object.defineProperties(getField("online"), {
        isOnlineNow : {
            get: function() { return getField("isOnlineNow"); },
            set: function(val) { setField("isOnlineNow", val); }
        },
        lastSeen : {
            get: function() { return setField("lastSeen"); },
            set: function(val) { getField("lastSeen", val); }
        },
        roomId: {
            get: function() { return setField("roomId"); },
            set: function(val) { getField("roomId", val); }
        },
        roomName: {
            get: function() { return setField("roomName"); },
            set: function(val) { getField("roomName", val); }
        }
    });

    /**
     * @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; } },
        lastChanged : { get : function() { return getField("lastChanged"); } },
        lastUpdated : { get : function() { return getField("lastUpdated"); } },
        uname : {
            get : function() { return getField("uname"); },
            set : function(val) { setField("uname", val); }
        },
        name : {
            get : function() { return getField("name") || getField("uname") || _uid.toString(); },
            set : function(val) { setField("name", val); }
        },
        note : {
            get : function() { return getField("note"); },
            set : function(val) { setField("note", val); }
        },
        age : {
            get : function() { return getField("age"); },
            set : function(val) { setField("age", val); }
        },
        gender : {
            get: function() { return getField("gender"); },
            set: function(val) { setField("gender", val); }
        },
        isPremium : {
            get: function() { return getField("isPremium"); },
            set: function(val) { setField("isPremium", val); }
        },
        isReal : {
            get: function() { return getField("isReal"); },
            set: function(val) { setField("isReal", val); }
        },
        isSuper : {
            get: function() { return getField("isSuper"); },
            set: function(val) { setField("isSuper", val); }
        },
        location : { get: function() { return getField("location"); } },
        online : { get: function() { return getField("online"); } }
    });

    /**
     * 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,
                age : this.age,
                gender : this.gender,
                isPremium : this.isPremium,
                isReal : this.isReal,
                isSuper : this.isSuper,
                location : this.location,
                online : this.online,
                lastChanged : this.lastChanged,
                lastUpdated : this.lastUpdated
            }));
        }
    },
    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.info(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')
    };
})();