CaffGeek/MBACNationals

View on GitHub
Web.Admin/2014/wordpress/wp-includes/js/tinymce/plugins/wpeditimage/plugin.js

Summary

Maintainability
F
3 days
Test Coverage
/* global tinymce */
tinymce.PluginManager.add( 'wpeditimage', function( editor ) {
    var toolbarActive = false;

    function parseShortcode( content ) {
        return content.replace( /(?:<p>)?\[(?:wp_)?caption([^\]]+)\]([\s\S]+?)\[\/(?:wp_)?caption\](?:<\/p>)?/g, function( a, b, c ) {
            var id, cls, w, cap, img, width,
                trim = tinymce.trim;

            id = b.match( /id=['"]([^'"]*)['"] ?/ );
            if ( id ) {
                b = b.replace( id[0], '' );
            }

            cls = b.match( /align=['"]([^'"]*)['"] ?/ );
            if ( cls ) {
                b = b.replace( cls[0], '' );
            }

            w = b.match( /width=['"]([0-9]*)['"] ?/ );
            if ( w ) {
                b = b.replace( w[0], '' );
            }

            c = trim( c );
            img = c.match( /((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)([\s\S]*)/i );

            if ( img && img[2] ) {
                cap = trim( img[2] );
                img = trim( img[1] );
            } else {
                // old captions shortcode style
                cap = trim( b ).replace( /caption=['"]/, '' ).replace( /['"]$/, '' );
                img = c;
            }

            id = ( id && id[1] ) ? id[1] : '';
            cls = ( cls && cls[1] ) ? cls[1] : 'alignnone';

            if ( ! w && img ) {
                w = img.match( /width=['"]([0-9]*)['"]/ );
            }

            if ( w && w[1] ) {
                w = w[1];
            }

            if ( ! w || ! cap ) {
                return c;
            }

            width = parseInt( w, 10 );
            if ( ! editor.getParam( 'wpeditimage_html5_captions' ) ) {
                width += 10;
            }

            return '<div class="mceTemp"><dl id="'+ id +'" class="wp-caption '+ cls +'" style="width: '+ width +'px">' +
                '<dt class="wp-caption-dt">'+ img +'</dt><dd class="wp-caption-dd">'+ cap +'</dd></dl></div>';
        });
    }

    function getShortcode( content ) {
        return content.replace( /<div (?:id="attachment_|class="mceTemp)[^>]*>([\s\S]+?)<\/div>/g, function( a, b ) {
            var out = '';

            if ( b.indexOf('<img ') === -1 ) {
                // Broken caption. The user managed to drag the image out?
                // Try to return the caption text as a paragraph.
                out = b.match( /<dd [^>]+>([\s\S]+?)<\/dd>/i );

                if ( out && out[1] ) {
                    return '<p>' + out[1] + '</p>';
                }

                return '';
            }

            out = b.replace( /<dl ([^>]+)>\s*<dt [^>]+>([\s\S]+?)<\/dt>\s*<dd [^>]+>([\s\S]*?)<\/dd>\s*<\/dl>/gi, function( a, b, c, cap ) {
                var id, cls, w;

                w = c.match( /width="([0-9]*)"/ );
                w = ( w && w[1] ) ? w[1] : '';

                if ( ! w || ! cap ) {
                    return c;
                }

                id = b.match( /id="([^"]*)"/ );
                id = ( id && id[1] ) ? id[1] : '';

                cls = b.match( /class="([^"]*)"/ );
                cls = ( cls && cls[1] ) ? cls[1] : '';
                cls = cls.match( /align[a-z]+/ ) || 'alignnone';

                cap = cap.replace( /\r\n|\r/g, '\n' ).replace( /<[a-zA-Z0-9]+( [^<>]+)?>/g, function( a ) {
                    // no line breaks inside HTML tags
                    return a.replace( /[\r\n\t]+/, ' ' );
                });

                // convert remaining line breaks to <br>
                cap = cap.replace( /\s*\n\s*/g, '<br />' );

                return '[caption id="'+ id +'" align="'+ cls +'" width="'+ w +'"]'+ c +' '+ cap +'[/caption]';
            });

            if ( out.indexOf('[caption') !== 0 ) {
                // the caption html seems broken, try to find the image that may be wrapped in a link
                // and may be followed by <p> with the caption text.
                out = b.replace( /[\s\S]*?((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)(<p>[\s\S]*<\/p>)?[\s\S]*/gi, '<p>$1</p>$2' );
            }

            return out;
        });
    }

    function extractImageData( imageNode ) {
        var classes, extraClasses, metadata, captionBlock, caption, link, width, height,
            dom = editor.dom,
            isIntRegExp = /^\d+$/;

        // default attributes
        metadata = {
            attachment_id: false,
            size: 'custom',
            caption: '',
            align: 'none',
            extraClasses: '',
            link: false,
            linkUrl: '',
            linkClassName: '',
            linkTargetBlank: false,
            linkRel: '',
            title: ''
        };

        metadata.url = dom.getAttrib( imageNode, 'src' );
        metadata.alt = dom.getAttrib( imageNode, 'alt' );
        metadata.title = dom.getAttrib( imageNode, 'title' );

        width = dom.getAttrib( imageNode, 'width' );
        height = dom.getAttrib( imageNode, 'height' );

        if ( ! isIntRegExp.test( width ) || parseInt( width, 10 ) < 1 ) {
            width = imageNode.naturalWidth || imageNode.width;
        }

        if ( ! isIntRegExp.test( height ) || parseInt( height, 10 ) < 1 ) {
            height = imageNode.naturalHeight || imageNode.height;
        }

        metadata.customWidth = metadata.width = width;
        metadata.customHeight = metadata.height = height;

        classes = tinymce.explode( imageNode.className, ' ' );
        extraClasses = [];

        tinymce.each( classes, function( name ) {

            if ( /^wp-image/.test( name ) ) {
                metadata.attachment_id = parseInt( name.replace( 'wp-image-', '' ), 10 );
            } else if ( /^align/.test( name ) ) {
                metadata.align = name.replace( 'align', '' );
            } else if ( /^size/.test( name ) ) {
                metadata.size = name.replace( 'size-', '' );
            } else {
                extraClasses.push( name );
            }

        } );

        metadata.extraClasses = extraClasses.join( ' ' );

        // Extract caption
        captionBlock = dom.getParents( imageNode, '.wp-caption' );

        if ( captionBlock.length ) {
            captionBlock = captionBlock[0];

            classes = captionBlock.className.split( ' ' );
            tinymce.each( classes, function( name ) {
                if ( /^align/.test( name ) ) {
                    metadata.align = name.replace( 'align', '' );
                }
            } );

            caption = dom.select( 'dd.wp-caption-dd', captionBlock );
            if ( caption.length ) {
                caption = caption[0];

                metadata.caption = editor.serializer.serialize( caption )
                    .replace( /<br[^>]*>/g, '$&\n' ).replace( /^<p>/, '' ).replace( /<\/p>$/, '' );
            }
        }

        // Extract linkTo
        if ( imageNode.parentNode && imageNode.parentNode.nodeName === 'A' ) {
            link = imageNode.parentNode;
            metadata.linkUrl = dom.getAttrib( link, 'href' );
            metadata.linkTargetBlank = dom.getAttrib( link, 'target' ) === '_blank' ? true : false;
            metadata.linkRel = dom.getAttrib( link, 'rel' );
            metadata.linkClassName = link.className;
        }

        return metadata;
    }

    function hasTextContent( node ) {
        return node && !! ( node.textContent || node.innerText );
    }

    function updateImage( imageNode, imageData ) {
        var classes, className, node, html, parent, wrap, linkNode,
            captionNode, dd, dl, id, attrs, linkAttrs, width, height,
            dom = editor.dom;

        classes = tinymce.explode( imageData.extraClasses, ' ' );

        if ( ! classes ) {
            classes = [];
        }

        if ( ! imageData.caption ) {
            classes.push( 'align' + imageData.align );
        }

        if ( imageData.attachment_id ) {
            classes.push( 'wp-image-' + imageData.attachment_id );
            if ( imageData.size && imageData.size !== 'custom' ) {
                classes.push( 'size-' + imageData.size );
            }
        }

        width = imageData.width;
        height = imageData.height;

        if ( imageData.size === 'custom' ) {
            width = imageData.customWidth;
            height = imageData.customHeight;
        }

        attrs = {
            src: imageData.url,
            width: width || null,
            height: height || null,
            alt: imageData.alt,
            title: imageData.title || null,
            'class': classes.join( ' ' ) || null
        };

        dom.setAttribs( imageNode, attrs );

        linkAttrs = {
            href: imageData.linkUrl,
            rel: imageData.linkRel || null,
            target: imageData.linkTargetBlank ? '_blank': null,
            'class': imageData.linkClassName || null
        };

        if ( imageNode.parentNode && imageNode.parentNode.nodeName === 'A' && ! hasTextContent( imageNode.parentNode ) ) {
            // Update or remove an existing link wrapped around the image
            if ( imageData.linkUrl ) {
                dom.setAttribs( imageNode.parentNode, linkAttrs );
            } else {
                dom.remove( imageNode.parentNode, true );
            }
        } else if ( imageData.linkUrl ) {
            if ( linkNode = dom.getParent( imageNode, 'a' ) ) {
                // The image is inside a link together with other nodes,
                // or is nested in another node, move it out
                dom.insertAfter( imageNode, linkNode );
            }

            // Add link wrapped around the image
            linkNode = dom.create( 'a', linkAttrs );
            imageNode.parentNode.insertBefore( linkNode, imageNode );
            linkNode.appendChild( imageNode );
        }

        captionNode = editor.dom.getParent( imageNode, '.mceTemp' );

        if ( imageNode.parentNode && imageNode.parentNode.nodeName === 'A' && ! hasTextContent( imageNode.parentNode ) ) {
            node = imageNode.parentNode;
        } else {
            node = imageNode;
        }

        if ( imageData.caption ) {

            id = imageData.attachment_id ? 'attachment_' + imageData.attachment_id : null;
            className = 'wp-caption align' + ( imageData.align || 'none' );

            if ( ! editor.getParam( 'wpeditimage_html5_captions' ) ) {
                width = parseInt( width, 10 );
                width += 10;
            }

            if ( captionNode ) {
                dl = dom.select( 'dl.wp-caption', captionNode );

                if ( dl.length ) {
                    dom.setAttribs( dl, {
                        id: id,
                        'class': className,
                        style: 'width: ' + width + 'px'
                    } );
                }

                dd = dom.select( '.wp-caption-dd', captionNode );

                if ( dd.length ) {
                    dom.setHTML( dd[0], imageData.caption );
                }

            } else {
                id = id ? 'id="'+ id +'" ' : '';

                // should create a new function for generating the caption markup
                html =  '<dl ' + id + 'class="' + className +'" style="width: '+ width +'px">' +
                    '<dt class="wp-caption-dt">' + dom.getOuterHTML( node ) + '</dt><dd class="wp-caption-dd">'+ imageData.caption +'</dd></dl>';

                if ( parent = dom.getParent( node, 'p' ) ) {
                    wrap = dom.create( 'div', { 'class': 'mceTemp' }, html );
                    dom.insertAfter( wrap, parent );
                    dom.remove( node );

                    if ( dom.isEmpty( parent ) ) {
                        dom.remove( parent );
                    }
                } else {
                    dom.setOuterHTML( node, '<div class="mceTemp">' + html + '</div>' );
                }
            }
        } else if ( captionNode ) {
            // Remove the caption wrapper and place the image in new paragraph
            parent = dom.create( 'p' );
            captionNode.parentNode.insertBefore( parent, captionNode );
            parent.appendChild( node );
            dom.remove( captionNode );
        }

        if ( wp.media.events ) {
            wp.media.events.trigger( 'editor:image-update', {
                editor: editor,
                metadata: imageData,
                image: imageNode
            } );
        }

        editor.nodeChanged();
        // Refresh the toolbar
        addToolbar( imageNode );
    }

    function editImage( img ) {
        var frame, callback, metadata;

        if ( typeof wp === 'undefined' || ! wp.media ) {
            editor.execCommand( 'mceImage' );
            return;
        }

        metadata = extractImageData( img );

        // Manipulate the metadata by reference that is fed into the PostImage model used in the media modal
        wp.media.events.trigger( 'editor:image-edit', {
            editor: editor,
            metadata: metadata,
            image: img
        } );

        frame = wp.media({
            frame: 'image',
            state: 'image-details',
            metadata: metadata
        } );

        wp.media.events.trigger( 'editor:frame-create', { frame: frame } );

        callback = function( imageData ) {
            editor.focus();
            editor.undoManager.transact( function() {
                updateImage( img, imageData );
            } );
            frame.detach();
        };

        frame.state('image-details').on( 'update', callback );
        frame.state('replace-image').on( 'replace', callback );
        frame.on( 'close', function() {
            editor.focus();
            frame.detach();
        });

        frame.open();
    }

    function removeImage( node ) {
        var wrap;

        if ( node.nodeName === 'DIV' && editor.dom.hasClass( node, 'mceTemp' ) ) {
            wrap = node;
        } else if ( node.nodeName === 'IMG' || node.nodeName === 'DT' || node.nodeName === 'A' ) {
            wrap = editor.dom.getParent( node, 'div.mceTemp' );
        }

        if ( wrap ) {
            if ( wrap.nextSibling ) {
                editor.selection.select( wrap.nextSibling );
            } else if ( wrap.previousSibling ) {
                editor.selection.select( wrap.previousSibling );
            } else {
                editor.selection.select( wrap.parentNode );
            }

            editor.selection.collapse( true );
            editor.nodeChanged();
            editor.dom.remove( wrap );
        } else {
            editor.dom.remove( node );
        }
        removeToolbar();
    }

    function addToolbar( node ) {
        var rectangle, toolbarHtml, toolbar, left,
            dom = editor.dom;

        removeToolbar();

        // Don't add to placeholders
        if ( ! node || node.nodeName !== 'IMG' || isPlaceholder( node ) ) {
            return;
        }

        dom.setAttrib( node, 'data-wp-imgselect', 1 );
        rectangle = dom.getRect( node );

        toolbarHtml = '<div class="dashicons dashicons-edit edit" data-mce-bogus="1"></div>' +
            '<div class="dashicons dashicons-no-alt remove" data-mce-bogus="1"></div>';

        toolbar = dom.create( 'div', {
            'id': 'wp-image-toolbar',
            'data-mce-bogus': '1',
            'contenteditable': false
        }, toolbarHtml );

        if ( editor.rtl ) {
            left = rectangle.x + rectangle.w - 82;
        } else {
            left = rectangle.x;
        }

        editor.getBody().appendChild( toolbar );
        dom.setStyles( toolbar, {
            top: rectangle.y,
            left: left
        });

        toolbarActive = true;
    }

    function removeToolbar() {
        var toolbar = editor.dom.get( 'wp-image-toolbar' );

        if ( toolbar ) {
            editor.dom.remove( toolbar );
        }

        editor.dom.setAttrib( editor.dom.select( 'img[data-wp-imgselect]' ), 'data-wp-imgselect', null );

        toolbarActive = false;
    }

    function isPlaceholder( node ) {
        var dom = editor.dom;

        if ( dom.hasClass( node, 'mceItem' ) || dom.getAttrib( node, 'data-mce-placeholder' ) ||
            dom.getAttrib( node, 'data-mce-object' ) ) {

            return true;
        }

        return false;
    }

    editor.on( 'init', function() {
        var dom = editor.dom,
            captionClass = editor.getParam( 'wpeditimage_html5_captions' ) ? 'html5-captions' : 'html4-captions';

        dom.addClass( editor.getBody(), captionClass );

        // Add caption field to the default image dialog
        editor.on( 'wpLoadImageForm', function( event ) {
            if ( editor.getParam( 'wpeditimage_disable_captions' ) ) {
                return;
            }

            var captionField = {
                type: 'textbox',
                flex: 1,
                name: 'caption',
                minHeight: 60,
                multiline: true,
                scroll: true,
                label: 'Image caption'
            };

            event.data.splice( event.data.length - 1, 0, captionField );
        });

        // Fix caption parent width for images added from URL
        editor.on( 'wpNewImageRefresh', function( event ) {
            var parent, captionWidth;

            if ( parent = dom.getParent( event.node, 'dl.wp-caption' ) ) {
                if ( ! parent.style.width ) {
                    captionWidth = parseInt( event.node.clientWidth, 10 ) + 10;
                    captionWidth = captionWidth ? captionWidth + 'px' : '50%';
                    dom.setStyle( parent, 'width', captionWidth );
                }
            }
        });

        editor.on( 'wpImageFormSubmit', function( event ) {
            var data = event.imgData.data,
                imgNode = event.imgData.node,
                caption = event.imgData.caption,
                captionId = '',
                captionAlign = '',
                captionWidth = '',
                wrap, parent, node, html, imgId;

            // Temp image id so we can find the node later
            data.id = '__wp-temp-img-id';
            // Cancel the original callback
            event.imgData.cancel = true;

            if ( ! data.style ) {
                data.style = null;
            }

            if ( ! data.src ) {
                // Delete the image and the caption
                if ( imgNode ) {
                    if ( wrap = dom.getParent( imgNode, 'div.mceTemp' ) ) {
                        dom.remove( wrap );
                    } else if ( imgNode.parentNode.nodeName === 'A' ) {
                        dom.remove( imgNode.parentNode );
                    } else {
                        dom.remove( imgNode );
                    }

                    editor.nodeChanged();
                }
                return;
            }

            if ( caption ) {
                caption = caption.replace( /\r\n|\r/g, '\n' ).replace( /<\/?[a-zA-Z0-9]+( [^<>]+)?>/g, function( a ) {
                    // No line breaks inside HTML tags
                    return a.replace( /[\r\n\t]+/, ' ' );
                });

                // Convert remaining line breaks to <br>
                caption = caption.replace( /(<br[^>]*>)\s*\n\s*/g, '$1' ).replace( /\s*\n\s*/g, '<br />' );
            }

            if ( ! imgNode ) {
                // New image inserted
                html = dom.createHTML( 'img', data );

                if ( caption ) {
                    node = editor.selection.getNode();

                    if ( data.width ) {
                        captionWidth = parseInt( data.width, 10 );

                        if ( ! editor.getParam( 'wpeditimage_html5_captions' ) ) {
                            captionWidth += 10;
                        }

                        captionWidth = ' style="width: ' + captionWidth + 'px"';
                    }

                    html = '<dl class="wp-caption alignnone"' + captionWidth + '>' +
                        '<dt class="wp-caption-dt">'+ html +'</dt><dd class="wp-caption-dd">'+ caption +'</dd></dl>';

                    if ( node.nodeName === 'P' ) {
                        parent = node;
                    } else {
                        parent = dom.getParent( node, 'p' );
                    }

                    if ( parent && parent.nodeName === 'P' ) {
                        wrap = dom.create( 'div', { 'class': 'mceTemp' }, html );
                        dom.insertAfter( wrap, parent );
                        editor.selection.select( wrap );
                        editor.nodeChanged();

                        if ( dom.isEmpty( parent ) ) {
                            dom.remove( parent );
                        }
                    } else {
                        editor.selection.setContent( '<div class="mceTemp">' + html + '</div>' );
                    }
                } else {
                    editor.selection.setContent( html );
                }
            } else {
                // Edit existing image

                // Store the original image id if any
                imgId = imgNode.id || null;
                // Update the image node
                dom.setAttribs( imgNode, data );
                wrap = dom.getParent( imgNode, 'dl.wp-caption' );

                if ( caption ) {
                    if ( wrap ) {
                        if ( parent = dom.select( 'dd.wp-caption-dd', wrap )[0] ) {
                            parent.innerHTML = caption;
                        }
                    } else {
                        if ( imgNode.className ) {
                            captionId = imgNode.className.match( /wp-image-([0-9]+)/ );
                            captionAlign = imgNode.className.match( /align(left|right|center|none)/ );
                        }

                        if ( captionAlign ) {
                            captionAlign = captionAlign[0];
                            imgNode.className = imgNode.className.replace( /align(left|right|center|none)/g, '' );
                        } else {
                            captionAlign = 'alignnone';
                        }

                        captionAlign = ' class="wp-caption ' + captionAlign + '"';

                        if ( captionId ) {
                            captionId = ' id="attachment_' + captionId[1] + '"';
                        }

                        captionWidth = data.width || imgNode.clientWidth;

                        if ( captionWidth ) {
                            captionWidth = parseInt( captionWidth, 10 );

                            if ( ! editor.getParam( 'wpeditimage_html5_captions' ) ) {
                                captionWidth += 10;
                            }

                            captionWidth = ' style="width: '+ captionWidth +'px"';
                        }

                        if ( imgNode.parentNode && imgNode.parentNode.nodeName === 'A' ) {
                            html = dom.getOuterHTML( imgNode.parentNode );
                            node = imgNode.parentNode;
                        } else {
                            html = dom.getOuterHTML( imgNode );
                            node = imgNode;
                        }

                        html = '<dl ' + captionId + captionAlign + captionWidth + '>' +
                            '<dt class="wp-caption-dt">'+ html +'</dt><dd class="wp-caption-dd">'+ caption +'</dd></dl>';

                        if ( parent = dom.getParent( imgNode, 'p' ) ) {
                            wrap = dom.create( 'div', { 'class': 'mceTemp' }, html );
                            dom.insertAfter( wrap, parent );
                            editor.selection.select( wrap );
                            editor.nodeChanged();

                            // Delete the old image node
                            dom.remove( node );

                            if ( dom.isEmpty( parent ) ) {
                                dom.remove( parent );
                            }
                        } else {
                            editor.selection.setContent( '<div class="mceTemp">' + html + '</div>' );
                        }
                    }
                } else {
                    if ( wrap ) {
                        // Remove the caption wrapper and place the image in new paragraph
                        if ( imgNode.parentNode.nodeName === 'A' ) {
                            html = dom.getOuterHTML( imgNode.parentNode );
                        } else {
                            html = dom.getOuterHTML( imgNode );
                        }

                        parent = dom.create( 'p', {}, html );
                        dom.insertAfter( parent, wrap.parentNode );
                        editor.selection.select( parent );
                        editor.nodeChanged();
                        dom.remove( wrap.parentNode );
                    }
                }
            }

            imgNode = dom.get('__wp-temp-img-id');
            dom.setAttrib( imgNode, 'id', imgId );
            event.imgData.node = imgNode;
        });

        editor.on( 'wpLoadImageData', function( event ) {
            var parent,
                data = event.imgData.data,
                imgNode = event.imgData.node;

            if ( parent = dom.getParent( imgNode, 'dl.wp-caption' ) ) {
                parent = dom.select( 'dd.wp-caption-dd', parent )[0];

                if ( parent ) {
                    data.caption = editor.serializer.serialize( parent )
                        .replace( /<br[^>]*>/g, '$&\n' ).replace( /^<p>/, '' ).replace( /<\/p>$/, '' );
                }
            }
        });

        dom.bind( editor.getDoc(), 'dragstart', function( event ) {
            var node = editor.selection.getNode();

            // Prevent dragging images out of the caption elements
            if ( node.nodeName === 'IMG' && dom.getParent( node, '.wp-caption' ) ) {
                event.preventDefault();
            }

            // Remove toolbar to avoid an orphaned toolbar when dragging an image to a new location
            removeToolbar();
        });

        // Prevent IE11 from making dl.wp-caption resizable
        if ( tinymce.Env.ie && tinymce.Env.ie > 10 ) {
            // The 'mscontrolselect' event is supported only in IE11+
            dom.bind( editor.getBody(), 'mscontrolselect', function( event ) {
                if ( event.target.nodeName === 'IMG' && dom.getParent( event.target, '.wp-caption' ) ) {
                    // Hide the thick border with resize handles around dl.wp-caption
                    editor.getBody().focus(); // :(
                } else if ( event.target.nodeName === 'DL' && dom.hasClass( event.target, 'wp-caption' ) ) {
                    // Trigger the thick border with resize handles...
                    // This will make the caption text editable.
                    event.target.focus();
                }
            });

            editor.on( 'click', function( event ) {
                if ( event.target.nodeName === 'IMG' && dom.getAttrib( event.target, 'data-wp-imgselect' ) &&
                    dom.getParent( event.target, 'dl.wp-caption' ) ) {

                    editor.getBody().focus();
                }
            });
        }
    });

    editor.on( 'ObjectResized', function( event ) {
        var parent, width,
            node = event.target,
            dom = editor.dom;

        if ( node.nodeName === 'IMG' ) {
            node.className = node.className.replace( /\bsize-[^ ]+/, '' );

            if ( parent = dom.getParent( node, '.wp-caption' ) ) {
                width = event.width || dom.getAttrib( node, 'width' );

                if ( width ) {
                    width = parseInt( width, 10 );

                    if ( ! editor.getParam( 'wpeditimage_html5_captions' ) ) {
                        width += 10;
                    }

                    dom.setStyle( parent, 'width', width + 'px' );
                }
            }
            // refresh toolbar
            addToolbar( node );
        }
    });

    editor.on( 'BeforeExecCommand', function( event ) {
        var node, p, DL, align,
            cmd = event.command,
            dom = editor.dom;

        if ( cmd === 'mceInsertContent' ) {
            // When inserting content, if the caret is inside a caption create new paragraph under
            // and move the caret there
            if ( node = dom.getParent( editor.selection.getNode(), 'div.mceTemp' ) ) {
                p = dom.create( 'p' );
                dom.insertAfter( p, node );
                editor.selection.setCursorLocation( p, 0 );
                editor.nodeChanged();

                if ( tinymce.Env.ie > 8 ) {
                    setTimeout( function() {
                        editor.selection.setCursorLocation( p, 0 );
                        editor.selection.setContent( event.value );
                    }, 500 );

                    return false;
                }
            }
        } else if ( cmd === 'JustifyLeft' || cmd === 'JustifyRight' || cmd === 'JustifyCenter' ) {
            node = editor.selection.getNode();
            align = cmd.substr(7).toLowerCase();
            align = 'align' + align;

            removeToolbar();

            if ( dom.is( node, 'dl.wp-caption' ) ) {
                DL = node;
            } else {
                DL = dom.getParent( node, 'dl.wp-caption' );
            }

            if ( DL ) {
                // When inside an image caption, set the align* class on dl.wp-caption
                if ( dom.hasClass( DL, align ) ) {
                    dom.removeClass( DL, align );
                    dom.addClass( DL, 'alignnone' );
                } else {
                    DL.className = DL.className.replace( /align[^ ]+/g, '' );
                    dom.addClass( DL, align );
                }

                return false;
            }

            if ( node.nodeName === 'IMG' ) {
                if ( dom.hasClass( node, align ) ) {
                    // The align class is being removed
                    dom.addClass( node, 'alignnone' );
                } else {
                    dom.removeClass( node, 'alignnone' );
                }
            }
        }
    });

    editor.on( 'keydown', function( event ) {
        var node, wrap, P, spacer,
            selection = editor.selection,
            keyCode = event.keyCode,
            dom = editor.dom;

        if ( keyCode === tinymce.util.VK.ENTER ) {
            // When pressing Enter inside a caption move the caret to a new parapraph under it
            node = selection.getNode();
            wrap = dom.getParent( node, 'div.mceTemp' );

            if ( wrap ) {
                dom.events.cancel( event ); // Doesn't cancel all :(

                // Remove any extra dt and dd cleated on pressing Enter...
                tinymce.each( dom.select( 'dt, dd', wrap ), function( element ) {
                    if ( dom.isEmpty( element ) ) {
                        dom.remove( element );
                    }
                });

                spacer = tinymce.Env.ie && tinymce.Env.ie < 11 ? '' : '<br data-mce-bogus="1" />';
                P = dom.create( 'p', null, spacer );

                if ( node.nodeName === 'DD' ) {
                    dom.insertAfter( P, wrap );
                } else {
                    wrap.parentNode.insertBefore( P, wrap );
                }

                editor.nodeChanged();
                selection.setCursorLocation( P, 0 );
            }
        } else if ( keyCode === tinymce.util.VK.DELETE || keyCode === tinymce.util.VK.BACKSPACE ) {
            node = selection.getNode();

            if ( node.nodeName === 'DIV' && dom.hasClass( node, 'mceTemp' ) ) {
                wrap = node;
            } else if ( node.nodeName === 'IMG' || node.nodeName === 'DT' || node.nodeName === 'A' ) {
                wrap = dom.getParent( node, 'div.mceTemp' );
            }

            if ( wrap ) {
                dom.events.cancel( event );
                removeImage( node );
                return false;
            }

            removeToolbar();
        }

        // Key presses will replace the image so we need to remove the toolbar
        if ( toolbarActive ) {
            if ( event.ctrlKey || event.metaKey || event.altKey ||
                ( keyCode < 48 && keyCode > 90 ) || keyCode > 186 ) {
                return;
            }

            removeToolbar();
        }
    });

    editor.on( 'mousedown', function( event ) {
        if ( editor.dom.getParent( event.target, '#wp-image-toolbar' ) ) {
            if ( tinymce.Env.ie ) {
                // Stop IE > 8 from making the wrapper resizable on mousedown
                event.preventDefault();
            }
        } else if ( event.target.nodeName !== 'IMG' ) {
            removeToolbar();
        }
    });

    editor.on( 'mouseup', function( event ) {
        var image,
            node = event.target,
            dom = editor.dom;

        // Don't trigger on right-click
        if ( event.button && event.button > 1 ) {
            return;
        }

        if ( node.nodeName === 'DIV' && dom.getParent( node, '#wp-image-toolbar' ) ) {
            image = dom.select( 'img[data-wp-imgselect]' )[0];

            if ( image ) {
                editor.selection.select( image );

                if ( dom.hasClass( node, 'remove' ) ) {
                    removeImage( image );
                } else if ( dom.hasClass( node, 'edit' ) ) {
                    editImage( image );
                }
            }
        } else if ( node.nodeName === 'IMG' && ! editor.dom.getAttrib( node, 'data-wp-imgselect' ) && ! isPlaceholder( node ) ) {
            addToolbar( node );
        } else if ( node.nodeName !== 'IMG' ) {
            removeToolbar();
        }
    });

    editor.on( 'cut', function() {
        removeToolbar();
    });

    editor.wpSetImgCaption = function( content ) {
        return parseShortcode( content );
    };

    editor.wpGetImgCaption = function( content ) {
        return getShortcode( content );
    };

    editor.on( 'BeforeSetContent', function( event ) {
        event.content = editor.wpSetImgCaption( event.content );
    });

    editor.on( 'PostProcess', function( event ) {
        if ( event.get ) {
            event.content = editor.wpGetImgCaption( event.content );
            event.content = event.content.replace( / data-wp-imgselect="1"/g, '' );
        }
    });

    return {
        _do_shcode: parseShortcode,
        _get_shcode: getShortcode
    };
});