XF 2.0 Custom avatar uploader

Lukas W.

Well-known member
I have created a custom entity that uses avatars just like users in XF do. They use the same avatar updater and it all worked fine for the first few beta versions, but lately it stopped working (I assume somewhere around XF2 Gold?). I can't really tell why though. Now, when I upload a new character avatar, I'd expect the script to replace all occurrences of the avatar on the current page (especially the one in the avatar cropper), but it fails to do so.

Here's my view class that is passed back to the script:
Code:
<?php

namespace RPGS\Pub\View\RPG\Character;

use XF\Mvc\View;

class AvatarUpdate extends View
{

    public function renderJson()
    {
        $visitor = \XF::visitor();
        $character = $this->params['character'];

        /** @var \RPGS\Template\Templater $templater */
        $templater = $this->renderer->getTemplater();

        $avatars = [];
        $avatarCodes = array_keys(\XF::app()->container('avatarSizeMap'));
        foreach ($avatarCodes AS $code) {
            $escape = false;
            $avatars[$code] = $templater->fnCharacterAvatar($templater, $escape, $character, $code, null, ['href' => '']);
        }

        return [
            'characterId' => $character->character_id,
            'avatars' => $avatars,
            'defaultAvatars' => ($visitor->getAvatarUrl('s') === null),
            'cropX' => $character->avatar_crop_x,
            'cropY' => $character->avatar_crop_y
        ];
    }
}

I've tried to return 'userId' as well to see if it maybe specifically looks for this key and prefixed the ID with a 'c', so it would return 'userId' => "c{$character->character_id}".

The avatars have the following HTML structure:
Code:
<a href="-urltocharacter-"
    class="avatar avatar--o"
    data-character-id="21"
    data-xf-click="overlay">
    <img src="-urltoavatar-" alt="Test" class="avatar-c21-o">
</a>

As above, I tried to change the data-character-id="21" to a with c prefixed data-user-id, but it didn't have any effects either.

And last but not least, this is the edit template:
Code:
<xf:title>{{ phrase('avatar') }}</xf:title>

<xf:css src="account_avatar.less" />
<xf:js prod="xf/avatar-compiled.js" dev="vendor/cropbox/jquery.cropbox.min.js, xf/avatar.js" />

<xf:form action="{{ link('rpg/characters/edit-avatar', $character) }}"
         upload="true"
         ajax="true"
         class="block"
         data-xf-init="avatar-upload">
    
    <div class="block-container">
        <ul class="block-body">
            <li class="block-row block-row--separated avatarControl">
                <div class="avatarControl-preview">
                    <div class="avatarCropper" style="width: {$maxSize}px; height: {$maxSize}px;">
                        {{ character_avatar($character, 'o', null, {
                            'style': {$maxDimension} . ':' . {$maxSize} . 'px; left: -' . {$x} . 'px; top: -' . {$y} . 'px;',
                            'data-x': {$x}, 'data-y': {$y}, 'data-size': {$maxSize},
                            'class': 'js-avatar js-avatarCropper',
                            'innerclass':  'js-croppedAvatar',
                            'forcetype': 'custom',
                            'data-xf-init': 'avatar-cropper',
                            'href': ''
                        }) }}
                        
                        <xf:hiddenval name="avatar_crop_x" class="js-avatarX">{$x}</xf:hiddenval>
                        <xf:hiddenval name="avatar_crop_y" class="js-avatarY">{$y}</xf:hiddenval>
                    </div>
                </div>
                <div class="avatarControl-inputs">
                    <xf:radio name="use_custom" id="useCustom" value="1">
                        <xf:option value="1"
                            label="{{ phrase('use_custom_avatar') }}"
                            hint="{{ phrase('drag_this_image_to_crop_it_then_click_update_avatar_to_confirm') }}">
                            <xf:dependent>
                                <label>{{ phrase('upload_new_custom_avatar:') }}</label>
                                <xf:upload name="upload" class="js-uploadAvatar" accept=".gif,.jpeg,.jpg,.jpe,.png" />
                                <dfn class="inputChoices-explain">
                                    {{ phrase('it_is_recommended_that_you_use_image_that_is_at_least_x_pixels', {
                                    'width': 400,
                                    'height': 400
                                    }) }}
                                </dfn>
                            </xf:dependent>
                        </xf:option>
                    </xf:radio>
                </div>
            </li>
        </ul>
        <xf:submitrow submit="{{ phrase('okay') }}" rowtype="simple" class="js-overlayClose">
            <xf:html>
                <xf:button type="submit" name="delete_avatar" value="1" class="js-deleteAvatar" icon="delete" />
            </xf:html>
        </xf:submitrow>
    </div>
</xf:form>

I can't really figure out what's off, so if someone sees my mistake, that'd be awesome.
 
I've managed to get this working by changing the avatar class from avatar-c21-o to avatar-uc21-o[/code] and [icode]'characterId' => $character->character_id to 'userId' => "c{$character->character_id}". It's a bit ugly in my eyes, still better though than deploying a whole script for it. I'd appreciate if there actually would be some kind of selector definition somewhere. Also wondering why it looks for the classes instead of the data-user-id-attribute.
 
Top Bottom