Seditio Source
Root |
./othercms/b2evolution_7.2.3/inc/users/views/_user_crop.form.php
<?php
/**
 * This file implements the UI view for the user picture crop form.
 *
 * This file is part of the evoCore framework - {@link http://evocore.net/}
 * See also {@link https://github.com/b2evolution/b2evolution}.
 *
 * @license GNU GPL v2 - {@link http://b2evolution.net/about/gnu-gpl-license}
 *
 * @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
 *
 * @package admin
 */

if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );

global
$display_mode, $Settings;

/**
 * @var instance of User class
 */
global $edited_User;
/**
 * @var current action
 */
global $action;
/**
 * @var user permission, if user is only allowed to edit his profile
 */
global $user_profile_only;
/**
 * @var the action destination of the form (NULL for pagenow)
 */
global $form_action;
/**
 * @var instance of User class
 */
global $current_User;
/**
 * @var File that should be cropped
 */
global $cropped_File;

global
$aspect_ratio, $content_width, $content_height;

$aspect_ratio = param( 'aspect_ratio', 'double' );
$content_width = param( 'content_width', 'integer' );
$content_height = param( 'content_height', 'integer' );

$original_image_size = explode( 'x', $cropped_File->get_image_size() );
$image_height = $original_image_size[1];
$image_width = $original_image_size[0];;
$min_avatar_size = $Settings->get( 'min_picture_size' );
$can_crop = ( $image_height >= $min_avatar_size && $image_width >= $min_avatar_size
       
&& ! ( $image_height == $min_avatar_size && $image_width == $min_avatar_size ) );

if(
$display_mode != 'js' )
{
   
// ------------------- PREV/NEXT USER LINKS -------------------
   
user_prevnext_links( array(
           
'user_tab' => 'avatar'
       
) );
   
// ------------- END OF PREV/NEXT USER LINKS -------------------
}

$Form = new Form( $form_action, 'user_checkchanges' );

if(
is_admin_page() )
{
   
$ctrl_param = '?ctrl=user&amp;user_tab=avatar&amp;user_ID='.$edited_User->ID;
   
$form_title = '';
   
$form_class = 'fform';
}
else
{
    global
$Collection, $Blog;
   
$form_title = '';
   
$form_class = 'bComment';
   
$ctrl_param = url_add_param( $Blog->gen_blogurl(), 'disp='.$disp );
}

if(
$display_mode != 'js' && is_admin_page() )
{
    if( !
$user_profile_only )
    {
       
echo_user_actions( $Form, $edited_User, $action );
    }

   
$form_text_title = TB_( 'Crop profile picture' ); // used for js confirmation message on leave the changed form
   
$form_title = get_usertab_header( $edited_User, '', $form_text_title );
}

$cropped_image_tag = $cropped_File->get_tag( '', '', '', '', 'original', '', '', '', '', '', '', '', '', '', 'none' );

// Display this error when JS is not enabled
echo '<noscript>'
       
.'<p class="error text-danger">'.TB_('Please activate Javascript in your browser in order to use this feature.').'</p>'
       
.'<style type="text/css">form#user_checkchanges { display:none }</style>'
   
.'</noscript>';

$Form->begin_form( $form_class, $form_title, array( 'title' => ( isset( $form_text_title ) ? $form_text_title : $form_title ) ) );

if(
is_admin_page() )
{
   
$Form->hidden_ctrl();
}
else
{
   
$Form->hidden( 'disp', $disp );
   
$Form->hidden( 'action', $action );
}
$Form->add_crumb( 'user' );
$Form->hidden( 'user_tab', param( 'user_tab_from', 'string', 'avatar' ) );
$Form->hidden( 'user_ID', isset( $edited_User ) ? $edited_User->ID : $current_User->ID );
$Form->hidden( 'file_ID', $cropped_File->ID );
$Form->hidden( 'image_crop_data', '' );
if( isset(
$Blog ) )
{
   
$Form->hidden( 'blog', $Blog->ID );
}

$close_icon = '';
if(
$display_mode == 'js' )
{
// Display a close link for popup window
   
$close_icon = action_icon( TB_('Close this window'), 'close', '', '', 0, 0, array( 'id' => 'close_button', 'class' => 'floatright' ) );
}

// Start displaying content

if( ! $can_crop )
{
    echo
'<div style="height: '.$content_height.'px; width: '. $content_width.'px; position=relative; text-align: center;">';
    echo
'<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">'.sprintf( TB_('Only images larger than %dx%d pixels can be cropped.'), $min_avatar_size, $min_avatar_size ).'</div>';
    echo
'</div>';
}
else
{
    echo
'<div id="user_crop_content" style="height: '.$content_height.'px; width: '. $content_width.'px;">';
    echo
'</div>';

   
$Form->button( array( 'type' => 'submit', 'name'=>'actionArray[crop]', 'value'=> TB_('Apply'), 'class' => 'SaveButton btn-primary' ) );
}
$Form->end_form();
if(
$can_crop )
{
?>
<style>
    #user_crop_workarea img {
        object-fit: contain;
        width: <?php echo $content_width;?>;
        height: <?php echo $content_height;?>;
        visibility: hidden;
    }

    div.jcrop-holder {
        margin: 0 auto;
        position: relative;
        top: 50%;
        transform: translateY(-50%);
    }
</style>

<script>
    var jcrop_api;
    var image_url = '<?php echo format_to_js( $cropped_File->get_url() ); ?>';
    var gutter = 10;
    var padding = 0;
    var content_height = <?php echo $content_height;?>;
    var content_width = <?php echo $content_width;?>;
    var show_large_preview = true;
    var show_small_preview = true;
    var large_preview_size = 128;
    var small_preview_size = 64;
    var preview_size;
    var preview_margin = 10;
    var preview_orientation = 'portrait';
    var aspect_ratio = <?php echo $aspect_ratio;?>;
    var render_mode = 'landscape';

    var workarea_height;
    var workarea_width;
    var workarea_aspect_ratio;

    var original_image_height = <?php echo $image_height;?>;
    var original_image_width = <?php echo $image_width;?>;
    var original_image_aspect_ratio = original_image_height / original_image_width;

    var size_ratio = 1;
    var working_image_height = null;
    var working_image_width = null;
    var working_image_aspect_ratio = null;

    var initial_crop_selection = [];

    //console.debug( 'Content: ', content_width, content_height );
    //console.debug( 'Original Image: ', original_image_width, original_image_height );


    function get_working_image_dimensions( w_height, w_width, image_aspect_ratio )
    { // We'll use this function to determine which mode will provide the larger working image
        var w_aspect_ratio = w_height / w_width;

        if( w_aspect_ratio > image_aspect_ratio )
        { // width is limiting dimension
            i_width = w_width;
            i_height = w_width * original_image_aspect_ratio;
        }
        else
        { // height is limiting dimension
            i_height = w_height;
            i_width = w_height / original_image_aspect_ratio;
        }

        i_area = i_width * i_height;

        return { height: i_height, width: i_width, area: i_area };
    }


    function init_layout()
    {
        var lw_width, lw_height, lw_area, lw_aspect_ratio;
        var pw_width, pw_height, pw_area, pw_aspect_ratio;
        var i_width, i_height, i_area;


        if( aspect_ratio < 1 && ( large_preview_size > ( content_width / 3 ) ) || aspect_ratio > 1 && ( large_preview_size > ( content_height / 3 ) ) )
        {
            preview_size = small_preview_size;
        }
        else
        {
            preview_size = large_preview_size;
        }

        // Try landscape mode first
        lw_width = content_width - preview_size - gutter - ( padding * 2 );
        lw_height = content_height - ( padding * 2 );
        lw_area = lw_width * lw_height;
        lw_aspect_ratio = lw_height / lw_width;

        var l_view = get_working_image_dimensions( lw_height, lw_width, original_image_aspect_ratio );

        // Now let's try portrait mode
        pw_height = content_height - preview_size - gutter - ( padding * 2 );
        pw_width = content_width - ( padding * 2 );
        pw_area = pw_width * pw_height;
        pw_aspect_ratio = pw_height / pw_width;

        var p_view = get_working_image_dimensions( pw_height, pw_width, original_image_aspect_ratio );

        // See what mode provides the largest working image
        if ( l_view.area > p_view.area )
        {
            render_mode = 'landscape';
        }
        else
        {
            render_mode = 'portrait';
        }

        // Determine if we can show all the preview images
        if( render_mode == 'portrait' )
        {
            if( ( content_width < original_image_width ? content_width : original_image_width ) > ( ( ( large_preview_size + preview_margin ) * 2 ) + ( ( small_preview_size + preview_margin ) * 2 ) ) )
            {
                show_large_preview = true;
                show_small_preview = true;
                preview_size = large_preview_size;
            }
            else if( ( ( content_width < original_image_width ? content_width : original_image_width ) > ( ( large_preview_size + preview_margin ) * 2 ) ) && ( ( 0.25 * content_height ) >= large_preview_size ) )
            {
                show_large_preview = true;
                show_small_preview = false;
                preview_size = large_preview_size;
            }
            else if( ( ( content_width < original_image_width ? content_width : original_image_width ) > ( ( small_preview_size + preview_margin ) * 2 ) ) && ( ( 0.25 * ( render_mode == 'landscape' ? content_width : content_height ) ) >= small_preview_size ) )
            {
                show_large_preview = false;
                show_small_preview = true;
                preview_size = small_preview_size;
            }
            else
            {
                show_large_preview = false;
                show_small_preview = false;
                preview_size = 0;
            }
        }
        else
        {
            if( ( content_height < original_image_height ? content_height : original_image_height ) > ( ( ( large_preview_size + preview_margin ) * 2 ) + ( ( small_preview_size + preview_margin ) * 2 ) ) )
            {
                show_large_preview = true;
                show_small_preview = true;
                preview_size = large_preview_size;
            }
            else if( ( ( content_height < original_image_height ? content_height : original_image_height ) > ( ( large_preview_size + preview_margin ) * 2 ) ) && ( ( 0.25 * ( content_width < content_height ? content_width : content_height ) ) >= large_preview_size ) )
            {
                show_large_preview = true;
                show_small_preview = false;
                preview_size = large_preview_size;
            }
            else if( ( ( content_height < original_image_height ? content_height : original_image_height ) > ( ( small_preview_size + preview_margin ) * 2 ) ) && ( ( 0.25 * ( content_width < content_height ? content_width : content_height ) ) >= small_preview_size ) )
            {
                show_large_preview = false;
                show_small_preview = true;
                preview_size = small_preview_size;
            }
            else if( ( content_height < original_image_height ? content_height : original_image_height ) > ( ( small_preview_size ) )
                    && ( ( content_width )  > ( lw_width + ( small_preview_size * 2 ) ) ) )
            { // This is a special case when there is not enough room for a vertical preview but a horizontal preview can be accomodated
                show_large_preview = false;
                show_small_preview = true;
                preview_size = small_preview_size;
                preview_orientation = 'landscape';
            }
            else
            {
                show_large_preview = false;
                show_small_preview = false;
                preview_size = 0;
            }
        }

        //console.debug( 'Render mode: ', render_mode );
        //console.debug( 'Show large preview: ', show_large_preview );
        //console.debug( 'Show small preview: ', show_small_preview );
        //console.debug( 'Preview Size: ', preview_size );
    }


    function init_workarea()
    {
        if( render_mode == 'portrait' )
        {
            workarea_height = content_height - preview_size - gutter - ( padding * 2 );
            workarea_width = content_width - ( padding * 2 );
        }
        else
        {
            workarea_height = ( content_height - ( padding * 2 ) );
            workarea_width = content_width - preview_size - gutter - ( padding * 2 );
        }
        workarea_aspect_ratio = ( workarea_height / workarea_width );

        //console.debug( 'Workarea: ', workarea_width, workarea_height );
    }


    function init_working_image()
    {
        if( workarea_aspect_ratio == original_image_aspect_ratio )
        {
            working_image_height = workarea_height;
            working_image_width = workarea_width;
            size_ratio = original_image_height / working_image_width;
            //console.debug( 'Limiting dimension: ', 'both' );
        }
        else if( workarea_aspect_ratio > original_image_aspect_ratio )
        {
            working_image_width = workarea_width;
            working_image_height = workarea_width * original_image_aspect_ratio;
            size_ratio = original_image_width / working_image_width;
            //console.debug( 'Limiting dimension: ', 'width' );
        }
        else
        {
            working_image_height = workarea_height;
            working_image_width = workarea_height / original_image_aspect_ratio;
            size_ratio = original_image_height / working_image_height;
            //console.debug( 'Limiting dimension: ', 'height' );
        }
        // Should be always equal to original image aspect ratio
        working_image_aspect_ratio = working_image_height / working_image_width;

        //console.debug( 'Image: ', working_image_width, working_image_height );
    }

    function init_crop_selection()
    {
        var crop_size;
        initial_crop_selection = [];

        if( original_image_aspect_ratio > 1 )
        {
            crop_size = original_image_width;
        }
        else
        {
            crop_size = original_image_height;
        }

        if( original_image_aspect_ratio > 1 )
        {
            initial_crop_selection.push( 0 );
            initial_crop_selection.push( 0 );
            initial_crop_selection.push( crop_size );
            initial_crop_selection.push( crop_size );
        }
        else
        {
            initial_crop_selection.push( ( original_image_width / 2 ) - ( crop_size / 2 ) );
            initial_crop_selection.push( ( original_image_height / 2 ) - ( crop_size / 2 ) );
            initial_crop_selection.push( ( original_image_width / 2 ) + ( crop_size / 2 ) );
            initial_crop_selection.push( ( original_image_height / 2 ) + ( crop_size / 2 ) );
        }

        //console.debug( 'Initial selection: ', initial_crop_selection );
    }


    function render_content()
    {
        var content = jQuery( 'div#user_crop_content' );

        var working_image = jQuery( '<img />', {
                src: image_url
            });

        var workarea = jQuery( '<div />', {
                id: 'user_crop_workarea',
                style: {
                    'background-color': '#f2f2f2',
                    height: workarea_height + 'px',
                    width: workarea_width + 'px'
                }
            });

        var previews = jQuery( '<div />', {
                id: 'user_crop_preview',
                style: {
                    'background-color': 'white',
                    height: preview_size + 'px',
                    'text-align': 'center',
                    'margin-top': gutter + 'px'
                }
            });

        // Large square preview
        var preview_lg_sq = jQuery( '<div />', {
                class: 'preview_cropped_image'
            }).css({
                width: '128px',
                height: '128px',
            }).append( working_image.clone() );

        // Small square preview
        var preview_sm_sq = jQuery( '<div />', {
                class: 'preview_cropped_image'
            }).css({
                    width: '64px',
                    height: '64px',
            }).append( working_image.clone() );

        // Large circle preview
        var preview_lg_c = jQuery( '<div />', {
                class: 'preview_cropped_image circle'
            }).css({
                    width: '128px',
                    height: '128px',
            }).append( working_image.clone() );

        // Small circle preview
        var preview_sm_c = jQuery( '<div />', {
                class: 'preview_cropped_image circle'
            }).css({
                    width: '64px',
                    height: '64px',
            }).append( working_image.clone() );

        if( render_mode == 'portrait' )
        { // Portrait
            workarea.css({
                'background-color': '#f2f2f2',
                height: workarea_height + 'px',
                width: workarea_width + 'px'
            });

            previews.css({
                'background-color': '#ffffff',
                height: preview_size + 'px',
                width: content_width + 'px',
                'text-align': 'center',
                'margin-top': gutter + 'px'
            });

            if( show_large_preview )
            {
                previews.append( preview_lg_sq );
            }

            if( show_small_preview )
            {
                previews.append( preview_sm_sq );
            }

            if( show_large_preview )
            {
                previews.append( preview_lg_c );
            }

            if( show_small_preview )
            {
                previews.append( preview_sm_c );
            }

            workarea.prepend( working_image );
            content.append( workarea );
            content.append( previews );

            preview_images = jQuery( 'div#user_crop_preview div.preview_cropped_image:not(:last-child)' );
            preview_images.css( 'margin-bottom', 0 );
            preview_images.css( 'margin-right', preview_margin + 'px' );
        }
        else
        { // Landscape
            workarea.css({
                'background-color': '#f2f2f2',
                float: 'left',
                width: workarea_width + 'px',
                height: workarea_height + 'px'
            });

            previews.css({
                'background-color': '#ffffff',
                float: 'left',
                width: ( preview_orientation == 'portrait' ? preview_size : ( ( preview_size + preview_margin ) * 2 ) ) + 'px',
                height: content_height + 'px',
                'text-align': 'center',
                'margin-left': gutter + 'px'
            });

            workarea.prepend( working_image );

            var preview_wrapper = jQuery( '<div />' );

            if( show_large_preview )
            {
                preview_wrapper.append( preview_lg_sq );
            }

            if( show_small_preview )
            {
                preview_wrapper.append( preview_sm_sq );
            }

            if( show_large_preview )
            {
                preview_wrapper.append( preview_lg_c );
            }

            if( show_small_preview )
            {
                preview_wrapper.append( preview_sm_c );
            }
            previews.append( preview_wrapper );

            content.append( workarea );
            content.append( previews );
            content.append( jQuery( '<div />', { style: { clear: 'both' } } ) );

            preview_images = jQuery( 'div#user_crop_preview div.preview_cropped_image:not(:last-child)' );

            if( preview_orientation == 'portrait' )
            {
                preview_images.css( 'margin-bottom', preview_margin + 'px' );
                preview_images.css( 'margin-right', 0 );
            }
            else
            {
                preview_images.css( 'margin-bottom', 0 );
                preview_images.css( 'margin-right', preview_margin + 'px' );
            }
        }

        // Adjust modal dimensions and content to minimize workarea margin
        var wah_margin = workarea_height - ( original_image_height < working_image_height ? original_image_height : working_image_height );
        var waw_margin = workarea_width - ( original_image_width < working_image_width ? original_image_width : working_image_width );
        var modal_dialog = jQuery( 'div.modal-dialog' ).length ? jQuery( 'div.modal-dialog' ) : jQuery( '#overlay_wrap' );
        var modal_body = jQuery( 'div.modal-body' ).length ? jQuery( 'div.modal-body' ) : jQuery( '#overlay_page' );
        var content = jQuery( 'div#user_crop_content' );

        //console.debug( 'Margin: ', wah_margin, waw_margin );
        //console.debug( 'Workarea: ', workarea_height, workarea_width );
        //console.debug( 'Working Image: ', working_image_height, working_image_width );

        workarea.css( 'height', ( workarea_height - wah_margin ) + 'px' );
        workarea.css( 'width', ( workarea_width - waw_margin ) + 'px' );
        content.css( 'height', ( content_height - wah_margin ) + 'px' );
        content.css( 'width', ( content_width - waw_margin + ( preview_orientation == 'landscape' ? preview_size + preview_margin + gutter : 0 ) ) + 'px' );
        modal_body.css( 'height', ( parseInt( modal_body.css( 'height' ) ) - wah_margin  ) + 'px' );
        modal_body.css( 'min-height', ( parseInt( modal_body.css( 'min-height' ) ) - wah_margin  ) + 'px' );
        modal_body.css( 'width', ( parseInt( modal_body.css( 'width' ) ) - waw_margin + ( preview_orientation == 'landscape' ? preview_size + preview_margin + gutter : 0 ) ) + 'px' );
        modal_dialog.css( 'height', ( parseInt( modal_dialog.css( 'height' ) ) - wah_margin ) + 'px' );
        modal_dialog.css( 'width', ( parseInt( modal_dialog.css( 'width' ) ) - waw_margin + ( preview_orientation == 'landscape' ? preview_size + preview_margin + gutter : 0 ) ) + 'px' );

        if( render_mode == 'portrait' )
        {
            previews.css( 'width', ( parseInt( previews.css( 'width' ) ) - waw_margin ) + 'px' );
        }
        else
        {
            previews.css( 'height', ( parseInt( previews.css( 'height' ) ) - wah_margin ) + 'px' );
        }
    }


    function update_preview( coords )
    {
        var target_cropped_image_width = original_image_width;
        var target_cropped_image_height = original_image_height;

        var percent_width = Math.ceil( coords.w / target_cropped_image_width * 10000 ) / 100;
        var percent_height = Math.ceil( coords.h / target_cropped_image_height * 10000 ) / 100;
        var percent_top = Math.ceil( coords.x / target_cropped_image_width * 10000 ) / 100;
        var percent_left = Math.ceil( coords.y / target_cropped_image_height * 10000 ) / 100;
        jQuery( 'input[name=image_crop_data]' ).val( percent_top + ':' + percent_left + ':' + percent_width + ':' + percent_height );

        var top = coords.y;
        var left = coords.x;
        if( coords.w > coords.h )
        { // Center a cropping area of horizontal image
            left += ( coords.w / 2 ) - ( coords.h / 2 );
        }
        else
        {
            var top_shift = ( coords.h - coords.w ) * 0.15;
            if( top + top_shift + coords.w < top + coords.h )
            { // top - 15%
                top += top_shift;
            }
        }

        jQuery( '.preview_cropped_image img' ).each( function()
        {
            var ratio = jQuery( this ).parent().width() / ( coords.w < coords.h ? coords.w : coords.h );

            jQuery( this ).css({
                width: Math.round( ratio * target_cropped_image_width ) + 'px',
                height: Math.round( ratio * target_cropped_image_height ) + 'px',
                marginLeft: '-' + Math.round( ratio * left ) + 'px',
                marginTop: '-' + Math.round( ratio * top ) + 'px'
            });
        });
    }


    function selection_release()
    { // Reset to initial selection if selection is released
        jcrop_api.setSelect( initial_crop_selection );
    }


    function init_jcrop_tool( image )
    {
        var min_avatar_size = <?php echo $min_avatar_size;?>;

        options = {
                    boxWidth: working_image_width,
                    boxHeight: working_image_height,
                    aspectRatio: 1,
                    minSize: [ min_avatar_size, min_avatar_size ],
                    onChange: update_preview,
                    onSelect: update_preview,
                    onRelease: selection_release
                };

        image.Jcrop( options, function() {
            jcrop_api = this;
            jcrop_api.setSelect( initial_crop_selection );
            image.css({ visibility: 'visible' });
        });
    }

    // Initialize content, workarea and working image
    init_layout();
    init_workarea();
    init_working_image();
    init_crop_selection();

    // Render everything
    render_content();

    // Initialize jcrop tool only after the image is fully loaded
    jQuery( '#user_crop_workarea img' ).on( 'load', function()
        {
            init_jcrop_tool( jQuery( this ) );
        });
</script>
<?php
}
?>