/*!

* froala_editor v2.3.3 (https://www.froala.com/wysiwyg-editor)
* License https://froala.com/wysiwyg-editor/terms/
* Copyright 2014-2016 Froala Labs
*/

(function (factory) {

if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
    // Node/CommonJS
    module.exports = function( root, jQuery ) {
        if ( jQuery === undefined ) {
            // require('jQuery') returns a factory that requires window to
            // build a jQuery instance, we normalize how we use modules
            // that require this pattern but the window provided is a noop
            // if it's defined (how jquery works)
            if ( typeof window !== 'undefined' ) {
                jQuery = require('jquery');
            }
            else {
                jQuery = require('jquery')(root);
            }
        }
        factory(jQuery);
        return jQuery;
    };
} else {
    // Browser globals
    factory(jQuery);
}

}(function ($) {

'use strict';
// Extend defaults.
$.extend($.FE.DEFAULTS, {
  dragInline: true
});

$.FE.PLUGINS.draggable = function (editor) {
  function _dragStart (e) {
    // Image with link.
    if (e.target && e.target.tagName == 'A' && e.target.childNodes.length == 1 && e.target.childNodes[0].tagName == 'IMG') {
      e.target = e.target.childNodes[0];
    }

    if (!$(e.target).hasClass('fr-draggable')) {
      e.preventDefault();
      return false;
    }

    $(e.target).addClass('fr-dragging');

    if (editor.opts.dragInline) {
      editor.$el.attr('contenteditable', true);
    }
    else {
      editor.$el.attr('contenteditable', false);
    }

    if (editor.opts.toolbarInline) editor.toolbar.hide();

    // Save in undo step if we cannot do.
    if (!editor.undo.canDo()) editor.undo.saveStep();

    if (!editor.browser.msie && !editor.browser.edge) {
      editor.selection.clear();
    }

    e.originalEvent.dataTransfer.setData('text', 'Froala');
  }

  function _tagOK (tag_under) {
    return !(tag_under && (tag_under.tagName == 'HTML' || tag_under.tagName == 'BODY' || editor.node.isElement(tag_under)));
  }

  function _setHelperSize (top, left, width) {
    if (editor.opts.iframe) {
      top += editor.$iframe.offset().top;
      left += editor.$iframe.offset().left;
    }

    if ($draggable_helper.offset().top != top) $draggable_helper.css('top', top);
    if ($draggable_helper.offset().left != left) $draggable_helper.css('left', left);
    if ($draggable_helper.width() != width) $draggable_helper.css('width', width);
  }

  function _positionHelper (e) {
    // The tag under the mouse cursor.
    var tag_under = editor.doc.elementFromPoint(e.originalEvent.pageX - editor.win.pageXOffset, e.originalEvent.pageY - editor.win.pageYOffset);
    if (!_tagOK(tag_under)) {

      // Look above for the closest tag.
      var top_offset = 0;
      var top_tag = tag_under;
      while (!_tagOK(top_tag) && top_tag == tag_under && e.originalEvent.pageY - editor.win.pageYOffset - top_offset > 0) {
        top_offset++;
        top_tag = editor.doc.elementFromPoint(e.originalEvent.pageX - editor.win.pageXOffset, e.originalEvent.pageY - editor.win.pageYOffset - top_offset);
      }
      if (!_tagOK(top_tag) || ($draggable_helper && editor.$el.find(top_tag).length === 0 && top_tag != $draggable_helper.get(0))) { top_tag = null; }

      // Look below for the closest tag.
      var bottom_offset = 0;
      var bottom_tag = tag_under;
      while (!_tagOK(bottom_tag) && bottom_tag == tag_under && e.originalEvent.pageY - editor.win.pageYOffset + bottom_offset < $(editor.doc).height()) {
        bottom_offset++;
        bottom_tag = editor.doc.elementFromPoint(e.originalEvent.pageX - editor.win.pageXOffset, e.originalEvent.pageY - editor.win.pageYOffset + bottom_offset);
      }

      if (!_tagOK(bottom_tag) || ($draggable_helper &&  editor.$el.find(bottom_tag).length === 0  && bottom_tag != $draggable_helper.get(0))) { bottom_tag = null; }

      if (bottom_tag == null && top_tag) tag_under = top_tag;
      else if (bottom_tag && top_tag == null) tag_under = bottom_tag;
      else if (bottom_tag && top_tag) {
        tag_under = (top_offset < bottom_offset ? top_tag : bottom_tag);
      }
      else {
        tag_under = null;
      }
    }

    // Stop if tag under is draggable helper.
    if ($(tag_under).hasClass('fr-drag-helper')) return false;

    // Get block parent.
    if (tag_under && !editor.node.isBlock(tag_under)) {
      tag_under = editor.node.blockParent(tag_under);
    }

    // Normalize TABLE parent.
    if (tag_under && ['TD', 'TH', 'TR', 'THEAD', 'TBODY'].indexOf(tag_under.tagName) >= 0) {
      tag_under = $(tag_under).parents('table').get(0);
    }

    // Normalize LIST parent.
    if (tag_under && ['LI'].indexOf(tag_under.tagName) >= 0) {
      tag_under = $(tag_under).parents('UL, OL').get(0);
    }

    if (tag_under && !$(tag_under).hasClass('fr-drag-helper')) {
      // Init helper.
      if (!$draggable_helper) {
        if (!$.FE.$draggable_helper) $.FE.$draggable_helper = $('<div class="fr-drag-helper"></div>');

        $draggable_helper = $.FE.$draggable_helper;

        editor.events.on('shared.destroy', function () {
          $draggable_helper.html('').removeData().remove();
          $draggable_helper = null;
        }, true);
      }

      var above;
      var mouse_y = e.originalEvent.pageY;

      if (mouse_y < $(tag_under).offset().top + $(tag_under).outerHeight() / 2) above = true;
      else above = false;

      var $tag_under = $(tag_under);
      var margin = 0 ;

      // Should go below and there is no tag below.
      if (!above && $tag_under.next().length === 0) {
        if ($draggable_helper.data('fr-position') != 'after' || !$tag_under.is($draggable_helper.data('fr-tag'))) {
          margin = parseFloat($tag_under.css('margin-bottom')) || 0;

          _setHelperSize(
            $tag_under.offset().top + $(tag_under).height() + margin / 2  - editor.$box.offset().top,
            $tag_under.offset().left - editor.win.pageXOffset - editor.$box.offset().left,
            $tag_under.width()
          );

          $draggable_helper.data('fr-position', 'after');
        }
      }
      else {
        // Should go below then we take the next tag.
        if (!above) {
          $tag_under = $tag_under.next();
        }

        if ($draggable_helper.data('fr-position') != 'before' || !$tag_under.is($draggable_helper.data('fr-tag'))) {
          if ($tag_under.prev().length > 0) {
            margin = parseFloat($tag_under.prev().css('margin-bottom')) || 0;
          }
          margin = Math.max(margin, parseFloat($tag_under.css('margin-top')) || 0);

          _setHelperSize(
            $tag_under.offset().top - margin / 2  - editor.$box.offset().top,
            $tag_under.offset().left - editor.win.pageXOffset  - editor.$box.offset().left,
            $tag_under.width()
          )

          $draggable_helper.data('fr-position', 'before');
        }
      }

      $draggable_helper.data('fr-tag', $tag_under);

      $draggable_helper.addClass('fr-visible');
      $draggable_helper.appendTo(editor.$box);
    }
    else if ($draggable_helper && editor.$box.find($draggable_helper).length > 0) {
      $draggable_helper.removeClass('fr-visible');
    }
  }

  function _dragOver (e) {
    e.originalEvent.dataTransfer.dropEffect = 'move';

    if (!editor.opts.dragInline) {
      e.preventDefault();

      _positionHelper(e);
    }

    else if (!_getDraggedEl() && (editor.browser.msie || editor.browser.edge)) {
      e.preventDefault();
    }
  }

  function _dragEnter (e) {
    e.originalEvent.dataTransfer.dropEffect = 'move';

    if (!editor.opts.dragInline) {
      e.preventDefault();
    }
  }

  function _documentDragEnd (e) {
    editor.$el.attr('contenteditable', true);
    var $draggedEl = editor.$el.find('.fr-dragging');

    if ($draggable_helper && $draggable_helper.hasClass('fr-visible') && editor.$box.find($draggable_helper).length) {
      _drop(e);
    }
    else if ($draggedEl.length) {
      e.preventDefault();
      e.stopPropagation();

      if ($draggable_helper && !$draggable_helper.hasClass('fr-visible')) {
        $draggedEl.removeClass('fr-dragging');
      }
    }

    if ($draggable_helper && editor.$box.find($draggable_helper).length) {
      $draggable_helper.removeClass('fr-visible');
    }
  }

  function _getDraggedEl () {
    var $draggedEl = null;

    // Search of the instance we're dragging from.
    for (var i = 0; i < $.FE.INSTANCES.length; i++) {
      $draggedEl = $.FE.INSTANCES[i].$el.find('.fr-dragging');
      if ($draggedEl.length) {
        return $draggedEl.get(0);
      }
    }
  }

  function _drop (e) {
    var $draggedEl;
    var inst;

    // Search of the instance we're dragging from.
    for (var i = 0; i < $.FE.INSTANCES.length; i++) {
      $draggedEl = $.FE.INSTANCES[i].$el.find('.fr-dragging');
      if ($draggedEl.length) {
        inst = $.FE.INSTANCES[i];
        break;
      }
    }

    if ($draggedEl.length) {
      // Cancel anything else.
      e.preventDefault();
      e.stopPropagation();

      if ($draggable_helper && $draggable_helper.hasClass('fr-visible') && editor.$box.find($draggable_helper).length) {
        $draggable_helper.data('fr-tag')[$draggable_helper.data('fr-position')]('<span class="fr-marker"></span>');
        $draggable_helper.removeClass('fr-visible');
      }
      else {
        var ok = editor.markers.insertAtPoint(e.originalEvent);
        if (ok === false) return false;
      }

      // Hide all popups.
      editor.popups.hideAll();

      // Save undo step if the current instance is different than the original one.
      if (inst != editor && !editor.undo.canDo()) {
        editor.undo.saveStep();
      }

      // Image with link.
      var $droppedEl = $draggedEl;
      if ($draggedEl.parent().is('A')) {
        $droppedEl = $draggedEl.parent();
      }

      // Replace marker with the dragged element.
      if (!editor.core.isEmpty()) {
        var $marker = editor.$el.find('.fr-marker');
        $marker.replaceWith($droppedEl);
        $draggedEl.after($.FE.MARKERS);
        editor.selection.restore();
      }
      else {
        editor.$el.html($droppedEl);
      }

      $draggedEl.removeClass('fr-dragging');
      editor.$el.find(editor.html.emptyBlockTagsQuery()).not('TD, TH, LI, .fr-inner').remove();
      editor.html.wrap();
      editor.html.fillEmptyBlocks();
      editor.undo.saveStep();

      if (editor.opts.iframe) editor.size.syncIframe();

      // Mark changes in the original instance as well.
      if (inst != editor) {
        inst.popups.hideAll();
        inst.$el.find(editor.html.emptyBlockTagsQuery()).not('TD, TH, LI, .fr-inner').remove();
        inst.html.wrap();
        inst.html.fillEmptyBlocks();
        inst.undo.saveStep();
        inst.events.trigger('element.dropped');

        if (inst.opts.iframe) inst.size.syncIframe();
      }

      editor.events.trigger('element.dropped', [$draggedEl]);

      // Stop bubbling.
      return false;
    }
  }

  /*
   * Initialize.
   */
  var $draggable_helper;
  function _init () {
    // Force drag inline when ENTER_BR is active.
    if (editor.opts.enter == $.FE.ENTER_BR) editor.opts.dragInline = true;

    // Starting to drag.
    editor.events.on('dragstart', _dragStart, true);

    // Inline dragging is off.
    editor.events.on('dragover', _dragOver, true);
    editor.events.on('dragenter', _dragEnter, true);

    // Document drop. Remove moving class.
    editor.events.on('document.dragend', _documentDragEnd, true);
    editor.events.on('document.drop', _documentDragEnd, true);

    // Drop.
    editor.events.on('drop', _drop, true);

    // Clean getting the HTML.
    editor.events.on('html.get', function (html) {
      html = html.replace(/<(div)((?:[\w\W]*?))class="([\w\W]*?)fr-drag-helper([\w\W]*?)"((?:[\w\W]*?))>((?:[\w\W]*?))<\/(div)>/g, '');

      return html;
    });
  }

  return {
    _init: _init
  }
}

}));