TFS Avatars

Detects locally-running image server to use for replacements of TFS avatars. Use http-server (https://www.npmjs.com/package/http-server) for node.js for simple image hosting. Recommend image size of 100x100.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name			TFS Avatars
// @namespace		DorkForce
// @version			4.4
// @description		Detects locally-running image server to use for replacements of TFS avatars. Use http-server (https://www.npmjs.com/package/http-server) for node.js for simple image hosting. Recommend image size of 100x100.
// @author			Dan Overlander
// @include			*tfs2*
// @require			https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @require         https://greasyfork.org/scripts/23115-tampermonkey-support-library/code/Tampermonkey%20Support%20Library.js?version=730858
// @require		    https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js
// ==/UserScript==

// Since v04.3: Replaced properName method with that from Gitlab script. TODO: extract script to tm library.
// Since v04.1: Tamperlibrary link updated. Removes Tamper Global script dependency
// Since v04.0: moving out setTamperIcon
// Since v03.0: Changed avatarHost to localhost
// Since v02.0: Changed avatarHost IP. Decreased TIMEOUT. Added history-image-icon class
// Since v01.0: Added missing classes from workitem history and links
// Since v00.0: Initial


(function() {
    'use strict';

    const TIMEOUT = 250;
    var toggle = {
            isMouseMoved: false,
            areClassesAdded: false
        },
        global = {
            triggerElement: '.menu-icon',
            scriptName: 'TFS Avatars',
            prefsName: 'TFSAvatarsPrefs',
            prefs: {},
            handlePrefsLocally: true,
            animationSpeed: (TIMEOUT/2),
            avatarHost: 'localhost:8080/', // for setPhoto
            pingPhoto: 'none', // pinging for setPhoto
            imageExt: '.png'
        },
        page = {
            initialize: function () {
                setTimeout(function () {
                    page.addClasses();
                    tm.addClasses();
                    tm.setTamperIcon(global);
                    page.setAvatars();
                }, TIMEOUT);
            },
            addClasses: function () {
                if (!toggle.areClassesAdded) {
                    toggle.areClassesAdded = true;

                    tm.addGlobalStyle('.identity-view-control { font-size:9px; line-height:10px; }');

                }
            },
            setAvatars: function () {
                tm.ping(global.avatarHost + global.pingPhoto + global.imageExt, function callback (response) {
                    if (response === 'responded') {
                        var avatarArray = [],
                            thisName = 'none',
                            thisImg;

                        tm.getContainer({
                            'el': '.user-picture-resolved'
                        }).then(function($container){
                            _.each($('.user-picture-resolved'), function (el) {
                                thisName = $(el).next().text();
                                thisImg = el;
                                utils.setProp(thisImg, thisName);
                            });
                        });

                        tm.getContainer({
                            'el': '.identity-picker-resolved'
                        }).then(function($container){
                            _.each($('.identity-picker-resolved'), function (el) {
                                thisName = $(el).text().replace('Focus on the selected item to change the value via a combo box', '');
                                thisImg = el.firstChild;
                                utils.setProp(thisImg, thisName);
                            });
                        });

                        tm.getContainer({
                            'el': '.history-identity-icon'
                        }).then(function($container){
                            _.each($('.history-identity-icon'), function (el) {
                                thisName = $(el).prop('alt');
                                thisName = utils.removeBrackets(thisName);
                                utils.setProp($(el), thisName);
                            });
                        });

                        tm.getContainer({
                            'el': '.la-user-icon'
                        }).then(function($container){
                            _.each($('.la-user-icon'), function (el) {
                                thisImg = $(el).find('img');
                                thisName = thisImg.prop('alt');
                                thisName = utils.removeBrackets(thisName);
                                utils.setProp(thisImg, thisName);
                            });
                        });

                        tm.getContainer({
                            'el': '.history-image-icon'
                        }).then(function($container){
                            _.each($('.history-image-icon'), function (el) {
                                thisImg = $(el);
                                thisName = thisImg.prop('alt');
                                thisName = utils.removeBrackets(thisName);
                                utils.setProp(thisImg, thisName);
                            });
                        });

                        tm.getContainer({
                            'el': '.ms-Persona'
                        }).then(function($container){
                            _.each($('.ms-Persona'), function (el) {
                                thisName = $(el).find('.persona-main-text-primary').text();
                                if (thisName == null || thisName === '') { // look for this value elsewhere in the DOM; in this case, the person's manager's element
                                    thisName = $(el).find('.persona-list-element-text-primary').text();
                                }
                                thisImg = $(el).find('img');
                                utils.setProp(thisImg, thisName);
                            });
                        });

                        tm.getContainer({
                            'el': '.profile-image'
                        }).then(function($container){
                            _.each($('.profile-image'), function (el) {
                                thisName = $(el).parent().parent().prop('outerHTML');
                                if (thisName.indexOf('aria-label') > -1) {
                                    var propStartIndex = thisName.indexOf('aria-label') + 12,
                                        propLength = thisName.indexOf('(', propStartIndex) - propStartIndex;
                                    thisName = thisName.substr(propStartIndex, propLength);
                                } else {
                                    thisName = '';
                                }

                                if (thisName == null || thisName === '') { // look for this value elsewhere in the DOM; in this case, the person's manager's element
                                    thisName = $(el).next().text();
                                }
                                thisImg = el;
                                utils.setProp(thisImg, thisName);
                            });
                        });

                        tm.getContainer({
                            'el': '.identity-picture'
                        }).then(function($container){
                            $('.identity-picture').each( function (key, value) {
                                var propStartIndex,
                                    propLength;
                                thisName = value.outerHTML; // generally, this is on the taskboard
                                if (thisName.indexOf('data-sip') > -1) {
                                    propStartIndex = thisName.indexOf('data-sip') + 10;
                                    propLength = thisName.indexOf('"', propStartIndex) - propStartIndex;
                                    thisName = thisName.substr(propStartIndex, propLength).replace('@Dell.com', '');
                                } else {
                                    thisName = '';
                                }

                                if (thisName == null || thisName === '') { // look for this value elsewhere in the DOM; in this case, within a dropdown
                                    thisName = $(this).parent().find('.title').text();
                                }

                                if (thisName == null || thisName === '') { // look for this value elsewhere in the DOM; in this case, in work-item history list
                                    thisName = $(this).parent().next().find('.discussion-messages-user').text();
                                }

                                if (thisName == null || thisName === '') { // look for this value elsewhere in the DOM; in this case, in team dashboard
                                    thisName = $(this).prop('alt');
                                    thisName = utils.removeBrackets(thisName);
                                }

                                thisImg = this;
                                utils.setProp(thisImg, thisName);
                            });
                        });

                        // On Query pages, in rows where Assigned- fields are shown. #AssignedFields
                        tm.getContainer({
                            'el': '.identity-grid-cell'
                        }).then(function($container){
                            var targetSpans = $('.identity-grid-cell').find('span');
                            targetSpans.each( function (key, value) {
                                thisName = utils.noTeam($(value).prop('innerText'));
                                if( (thisName.length > 2) && $(value).prop('innerHTML').indexOf('replacedName') === -1 ) {
                                    $(value).parent().parent().css('padding', '0px');
                                    $(value).parent().prop('innerHTML', '<span title="' + thisName + '" class="replacedName" style="background-image: url(\'http://' + global.avatarHost + thisName + global.imageExt + '\');">&nbsp;</span>' + thisName.replace(', ', '<br>').replace(' - Dell Team', '').replace(/([0-9])\w+/, '').replace(/([0-9])/, ''));
                                    $('.replacedName').css(
                                        {
                                            'top': '-2px',
                                            'position': 'relative',
                                            'height': '27px',
                                            'width': '27px',
                                            'display': 'block',
                                            'background-size': '27px 27px',
                                            'float': 'left'
                                        }
                                    );
                                }
                            });
                            setTimeout(page.setAvatars, (TIMEOUT*5));
                        });


                    }
                });
            }
        },
        utils = {
            noTeam: function(thisName) {
                return thisName.replace(' - Dell Team', '');
            },
            setProp: function(thisImg, thisName) {
                if (thisName != null && thisName != '' && thisName != 'undefined') {
                    thisName = utils.noTeam(thisName);
                    thisName = utils.properName(thisName);
                    $(thisImg).prop('src', 'http://' + global.avatarHost + thisName + global.imageExt);
                }
            },
            properName: function(thisName) {
                var firstName = '',
                    lastName = '',
                    midName = '';

                thisName = thisName
                    .replace('https://gitlab.dell.com/', '')
                    .replace(' - Dell Team', '')
                    .replace('\'s avatar', '')
                    .replace('Assigned to ', '')
                    .replace('Avatar for ', '')
                    .replace('@', '')
                    .replace(/@/g, '')
                    .replace(/\//g, '')
                    .replace(/_/g, '-');
                firstName = thisName.substring(0, thisName.indexOf('-'));
                lastName = thisName.substring(thisName.indexOf('-')+1, thisName.length);
                if ((firstName.length === 0 && lastName.length === 0)) {
                    return;
                }
                if (firstName.length > 0 && lastName.length > 0 && thisName.indexOf(',') < 0) {
                    thisName = lastName + ', ' + firstName;
                }
                if (thisName.indexOf('-') > 0) {
                    midName = thisName.substring(0, thisName.indexOf('-'));
                    thisName = thisName.substring(thisName.indexOf('-')+1, thisName.length);
                    thisName = thisName + ' ' + midName;
                }
                while (thisName.indexOf('  ') > 0) {
                    thisName = thisName.replace(/\s\s/, ''); // no double spaces
                }
                thisName = thisName
                    .replace(/(\r\n\t|\n|\r\t)/gm,'') // no line breaks or tabs
                    .replace(/ ,/, ',') // no spaces before commas
                    .replace(/\%20/, '') // no %20 characters
                    .replace(/Americas/g, '')
                    .trim(); // seriously, no extra spaces
                thisName = thisName.replace(',', ', ').replace('  ', ' '); // there's probably a less-stupid way of REALLY making sure it's always "COMMA SPACE"
                return thisName;
            },
            removeBrackets(thisName) {
                if (thisName == null) {
                    return;
                }
                var propLength = thisName.indexOf('<') - 1;
                thisName = thisName.substr(0, propLength);
                return thisName;
            }
        };

    /*
     * Global functions
     */


    function initScript () {
        tm.getContainer({
            'el': global.triggerElement,
            'max': 100,
            'spd': 1000
        }).then(function($container){
            page.initialize();
        });
    }
    initScript();

    $(document).mousemove(function(e) {
        if (!global.isMouseMoved) {
            global.isMouseMoved = true;
            setTimeout(function() {
                global.isMouseMoved = false;
            }, TIMEOUT * 2);
            initScript();
        }
    });

})();