Render modal from theme client-side plugin API

Well, just discover how model was passed to the showModal function and it unlocked a tons of things in my head :stuck_out_tongue:

Now I’m quite happy with what I have and assume it’s properly implemented according to core guidelines.

<script type="text/javascript" src="https://cf.eve-oj.com/js/EVEoj-0.3.x.min.js"></script>
<script type="text/javascript">
    var SDEVer = 201611140,
        SDD = EVEoj.SDD.Create('json', {'path': 'https://cf.eve-oj.com/sdd/' + SDEVer});
</script>
<script type="text/x-handlebars" data-template-name="modal/eve-sde-modal">
    {{#d-modal-body title="eve_sde_modal_title" class="eve-sde-modal"}}
    <p data-typeid="{{ model.type_id }}">{{{ model.description }}}</p>
    {{#if model.attributes.shield }}
    <h4>Shield</h4>
    <table>
        <tbody>
            <tr>
                {{#each model.attributes.shield as |attribute|}}
                <td>
                    <img src="{{ attribute.img.src }}" alt="{{ attribute.img.alt }}" /> {{ attribute.value }}
                </td>
                {{/each}}
            </tr>
        </tbody>
    </table>
    {{/if}}
    {{#if model.attributes.shield }}
    <h4>Armor</h4>
    <table>
        <tbody>
            <tr>
                {{#each model.attributes.armor as |attribute|}}
                <td>
                    <img src="{{ attribute.img.src }}" alt="{{ attribute.img.alt }}" /> {{ attribute.value }}
                </td>
                {{/each}}
            </tr>
        </tbody>
    </table>
    {{/if}}
    {{#if model.attributes.shield }}
    <h4>Hull</h4>
    <table>
        <tbody>
            <tr>
                {{#each model.attributes.hull as |attribute|}}
                <td>
                    <img src="{{ attribute.img.src }}" alt="{{ attribute.img.alt }}" /> {{ attribute.value }}
                </td>
                {{/each}}
            </tr>
        </tbody>
    </table>
    {{/if}}
    {{/d-modal-body}}
</script>
<script type="text/discourse-plugin" version="0.8.24">
    const ESI_BASE_URI = 'https://esi.evetech.net';
    const RESISTS = [109, 110, 111, 113, 267, 268, 269, 270, 271, 272, 273, 274];
    const showModal = require('discourse/lib/show-modal').default;
    let currentLocale = I18n.currentLocale();

    // EvE Online Magic SDE
    api.onAppEvent('modal:body-shown', msg => {
        if (msg.title !== 'eve_sde_modal_title')
            return;
            
        var typeID = $('.modal-body p').attr('data-typeid');
        $('.modal-header .title h3 img').remove();
        $('.modal-header .title h3').prepend(
            $('<img>').attr('src', `//image.eveonline.com/Type/${typeID}_32.png`)
                      .attr('alt', 'Icon')
                      .css('margin-right', '10px'));
    });
    
    api.decorateCooked(function(cooked) {
        SDD.LoadMeta()
            .then(function(arg) {
                return arg.source.GetTable('invTypes').Load();
            })
            .then(function(arg) {
                cooked.find('a[href="#evesde"]').each(function() {
                    var typeName = $(this).text();
                    results = _.filter(arg.table.data, function(entry) {
                        return entry[arg.table.c.typeName] === typeName;
                    });
                
                    if (results.length > 0) {
                        $(this).attr('data-typeid', results[0][arg.table.c.typeID]);
                        $(this).on('click', function() {
                            var typeID  = $(this).attr('data-typeid');
                            var typeUri = ESI_BASE_URI + '/latest/universe/types/' + typeID + '/';
                        
                            $.ajax({
                                data : {
                                    language: 'fr'
                                },
                                dataType: 'json',
                                headers: {
                                    'Accept-Language': 'fr',
                                    'X-User-Agent': 'discourse/1.0.0 (Warlof Tutsimo - Daerie Inc. - Get Off My Lawn)'
                                },
                                type: 'GET',
                                url: typeUri
                            }).done(function(data) {
                                SDD.LoadMeta()
                                    .then(function(arg) {
                                        return arg.source.GetTable('dgmAttributeTypes').Load();
                                    })
                                    .then(function(arg) {
                                        var sdeModel = {
                                            'type_id': 0,
                                            'description': '',
                                            'attributes': {
                                                'shield': [],
                                                'armor': [],
                                                'hull': []
                                            }
                                        };
                                        
                                        _.each(data.dogma_attributes, function(dgmAttribute) {
                                            if (RESISTS.indexOf(dgmAttribute.attribute_id) >= 0) {
                                                results = _.filter(arg.table.data, function(entry) {
                                                    return entry[arg.table.c.attributeID] === dgmAttribute.attribute_id;
                                                });
                                                
                                                if (results.length > 0) {
                                                    var attribute = {
                                                        'id': 0,
                                                        'name': '',
                                                        'value': '',
                                                        'percent': 0,
                                                        'img': {
                                                            'alt': '',
                                                            'src': ''
                                                        }
                                                    };
                                                    
                                                    switch (results[0][arg.table.c.iconID]) {
                                                        case 1393:
                                                            attribute.img.src = 'https://forums.clandaerie.com/uploads/default/original/1X/a948a8f3d0ac5a1628c110071aceef976db0fae5.png';
                                                            break;
                                                        case 1394:
                                                            attribute.img.src = 'https://forums.clandaerie.com/uploads/default/original/1X/4d8ef4c39d6baa27845ff8931c63fc4c08cc7bbb.png';
                                                            break;
                                                        case 1395:
                                                            attribute.img.src = 'https://forums.clandaerie.com/uploads/default/original/1X/281dbfadd89530cc1142a4b93fdc7ada671297eb.png';
                                                            break;
                                                        case 1396:
                                                            attribute.img.src = 'https://forums.clandaerie.com/uploads/default/original/1X/b3f1e97f6144ec32c601294bfe2a2abc7cd9adfd.png';
                                                            break;
                                                    }
                                                    
                                                    attribute.id = dgmAttribute.attribute_id;
                                                    attribute.name = results[0][arg.table.c.displayName];
                                                    attribute.value = dgmAttribute.value;
                                                    attribute.percent = Math.round((1 - attribute.value) * 100);
                                                    attribute.img.alt = attribute.name.replace(/Armor|Shield|Structure/gi, '').trim();
                                                    
                                                    switch (results[0][arg.table.c.categoryID]) {
                                                        // Shield
                                                        case 2:
                                                            sdeModel.attributes.shield.push(attribute);
                                                            break;
                                                        // Armor
                                                        case 3:
                                                            sdeModel.attributes.armor.push(attribute);
                                                            break;
                                                        // Structure
                                                        case 4:
                                                            sdeModel.attributes.hull.push(attribute);
                                                            break;
                                                    }
                                                }
                                            }
                                        });
                                        
                                        sdeModel.type_id = typeID;
                                        sdeModel.description = data.description
                                            .replace(/\r\n/gi, '<br/>')
                                            .replace(/\n\n/gi, '<br/>')
                                            .replace(/\n/gi, '<br/>')
                                            .replace(/<color='0xff([a-f0-9]{6})'>([a-z0-9,.']+)<\/color>/gmi, function(match, p1, p2, offset, string) {
                                                return `<span style="color: #${p1};">${p2}</span>`;
                                            })
                                            .replace(/<a href=showinfo:([0-9]+)>([éèàçù \w]+)<\/a>/gmi, function(match, p1, p2, offset, string) {
                                                return p2;
                                            });
                                            
                                        I18n.translations[currentLocale].js.eve_sde_modal_title = data.name;
                                        
                                        showModal('eveSdeModal', {
                                            'model': sdeModel
                                        });
                                    });
                            });
                        });
                    }
                });
            });
    }, {onlyStream: true});
</script>