fafranco82 / ArkhamDB Utils

// ==UserScript==
// @name         ArkhamDB Utils
// @namespace    http://franco.nom.es
// @version      0.2
// @description  Utilidades para ArkhamDB
// @updateURL    https://openuserjs.org/meta/fafranco82/ArkhamDB_Utils.meta.js
// @author       fafranco82
// @match        http://*.arkhamdb.com/*
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery.rest/1.0.2/jquery.rest.min.js
// @require      https://cdn.rawgit.com/caolan/async/master/dist/async.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js
// @require      https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js
// @require      https://cdn.rawgit.com/padolsey-archive/jquery.fn/master/sortElements/jquery.sortElements.js
// @grant        none
// ==/UserScript==

(function($) {
    'use strict';
    
    var lo = _.noConflict();
    
    var nest = function(seq, keys) {
        if(!keys.length) {
            return seq;
        } else {
            var first = keys[0];
            var rest = keys.slice(1);
            return lo.mapValues(lo.groupBy(seq, first), function(value) {
                return nest(value, rest);
            });
        }
    };

    lo.mixin({nest: nest});
    
    window.lo = lo;
    
    $(document).ready(function($) {
        $('nav.navbar').removeClass('navbar-static-top').addClass('navbar-fixed-top');
        $('body').css('margin-top', '90px');
        
        var options = {
            links: {
                'position': {
                    text: 'Posicionar',
                    click: function(callback) {
                        var $d = loading('Calculando posiciones...');
                        var deck_cards = lo(app.data.cards.find({
                            type_code: {$in: ['asset', 'event', 'skill']},
                            restrictions: {$exists: false}
                        })).reduce(function(acc, card) {
                            var number = card.quantity / 2;
                            if(card.pack_code=='core')
                                number = number * 2;
                            for(var i=0;i < number; i++) {
                                acc.push(card);
                            }
                            return acc;
                        }, []);                        
                        deck_cards = lo(deck_cards).orderBy(['faction_code', 'type_code', 'code']).nest(['faction_code', 'type_code']).value();
                        var investigator_cards = lo(app.data.cards.find({
                            type_code: 'investigator'
                        })).orderBy(['faction_code', 'code']).nest(['faction_code']).mapValues(function(cards, faction_code) {
                            return lo.reduce(cards, function(acc, i) {
                                acc.push(i);
                                app.data.cards.find({code: {$in: lo.keys(i.deck_requirements.card)}}).forEach(function(r) {
                                    acc.push(r);
                                });
                                return acc;
                            }, []);
                        }).value();
                        async.each($('[data-code]:visible'), function(elem, done) {
                            var card = app.data.cards.findById($(elem).data('code'));
                            var idx = lo.findIndex(deck_cards[card.faction_code][card.type_code], {code: card.code});
                            if(idx < 0 && lo.has(card, 'restrictions.investigator')) {
                                var ref = app.data.cards.findById(card.restrictions.investigator[0]);
                                idx = lo.findIndex(investigator_cards[ref.faction_code], {code: card.code});
                            }
                            if(idx >= 0) {
                                var sheet = parseInt(idx / 18) + 1;
                                var sheet_idx = idx % 18;
                                var side = parseInt(sheet_idx / 9);
                                var pocket = (sheet_idx % 9) + 1;
                                var text = '[' + sheet+'-'+(side ? 'B' : 'A')+'-'+pocket + ']';
                                $(elem).find('span.position').remove();
                                $('<span>').addClass('position').css('margin-right','0.1em').text(text).prependTo(elem);
                            }
                            done();
                        }, function(err) {
                            $d.close();
                            if(callback && typeof callback==='function')
                                callback();
                        });
                    }
                },
                'order': {
                    text: 'Ordenar',
                    click: function(callback) {
                        var tw = {'investigator': 0, 'asset': 1, 'event': 2, 'skill': 3};
                        var fw = ['neutral', 'guardian', 'seeker', 'rogue', 'mystic', 'survivor'];
                        var $d = loading('Ordenando...');
                        async.each($('div > [data-code]').closest('div').parent().closest('div'), function(root, done) {
                            $('div > [data-code]', root).sortElements(function(a, b) {
                                var ca = app.data.cards.findById($(a).data('code'));
                                var cb = app.data.cards.findById($(b).data('code'));
                                if(ca.faction_code==cb.faction_code) {
                                    if(ca.type_code==cb.type_code) {
                                        return ca.code < cb.code ? -1 : (ca.code > cb.code ? 1 : 0);
                                    } else {
                                        return tw[ca.type_code] < tw[cb.type_code] ? -1 : 1;
                                    }
                                } else {
                                    return fw.indexOf(ca.faction_code) < fw.indexOf(cb.faction_code) ? -1 : 1;
                                }
                            }, function() {
                                return $(this).closest('div').get(0);
                            });
                            done();
                        }, function(err) {
                            $d.close();
                            if(callback && typeof callback==='function')
                                callback();
                        });
                    }
                },
                'order_position': {
                    text: 'Ordenar y posicionar',
                    click: function() {
                        async.series([
                            options.links.order.click,
                            options.links.position.click
                        ], function(err) {
                        });
                    }
                }
            }
        };
        
        var dropdown = Handlebars.compile(
            '<li> ' +
            '    <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> ' +
            '    	<span class="fa fa-cog"></span> ' +
            '    	<span class="caret"></span> ' +
            '    </a> ' +
            '    <ul class="dropdown-menu"> ' +
            '    	{{#each links}} ' +
            '    	<li> ' +
            '    		<a class="util" href="#" data-link="{{@key}}">{{this.text}}</a> ' +
            '    	</li> ' +
            '    	{{/each}} ' +
            '    </ul> ' +
            '</li> ');
        
        $(dropdown(options)).appendTo('ul.navbar-right').on('click', 'a.util', function(e) {
            options.links[$(e.target).data('link')].click();
        });
        
    });
    
    var loadingHtml = Handlebars.compile(
            '<div class="modal" data-backdrop="static"> ' +
            '	<div class="modal-dialog"> ' +
            '		<div class="modal-content"> ' +
            '			<div class="modal-body"> ' +
            '				<div class="row"> ' +
            '					<div class="col-xs-12 text-center"> ' +
            '						<span class="fa fa-spinner fa-spin fa-5x"></span> ' +
            '					</div> ' +
            '				</div> ' +
            '				<div class="row"> ' +
            '					<div class="col-xs-12 text-center"> ' +
            '						<h4>{{texto}}</h4> ' +
            '					</div> ' +
            '				</div> ' +
            '			</div> ' +
            '		</div> ' +
            '	</div> ' +
            '</div> ');
    
    function loading(text) {
        var $d = $(loadingHtml({texto:text})).appendTo('body').modal();
        return {
            "close": function() {
                $d.modal('hide').remove();
            }
        };
    }
    
})(jQuery);