html-utils

utils for DOM manipulation and fetching info of a webpage

Tính đến 31-05-2016. Xem phiên bản mới nhất.

Script này sẽ không được không được cài đặt trực tiếp. Nó là một thư viện cho các script khác để bao gồm các chỉ thị meta // @require https://updategreasyfork.deno.dev/scripts/20131/128690/html-utils.js

// extend HtmlFactory
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
     * @returns {ElType} The 'select' HTML element
     */
    var createSelectUsers = function(users, id) {
        var elSelect = HtmlFactory.newSelect('smallselect', id);
        var _onchangeCallback;
        /**
         * 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);
            }
        };
        /**
         * The options will be regenerated by the 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;
            sortUsers.sort(function (a, b) {
                if (a.user.uname < b.user.uname) { return  -1; }
                if (a.user.uname > b.user.uname) { return 1; }
                return 0;
            });
            sortUsers.forEach(function (opt, i) {
                elSelect[i].text = opt.user.uname;
                elSelect[i].value = opt.user.uid;
                elSelect[i].user = opt.user;
                elSelect[i].selected = opt.selected;
            });
        };
        elSelect.updateUsers(users);
        return elSelect;
    };
    return {
        newButtonSmall : createButtonSmall,
        newButtonTiny : createButtonTiny,
        newSelectUsers : createSelectUsers
    }
})();

Object.keys(HtmlFactoryExtension).forEach(function (propName) {
    HtmlFactory[propName] = HtmlFactoryExtension[propName];
});

//extend Page
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];
});


/**
 * @name uidType
 * @type string|number
 */

/**
 * Represents a camamba user.
 * Intitially tries to load the User from the database that has the given uid.
 * @constructor
 * @param {uidType} 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 {{}<uidType,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);
    }
};