| /**
 * Quirks.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */
/**
 * This class contains various fixes for browsers. These issues can not be feature
 * detected since we have no direct control over the clipboard. However we might be able
 * to remove some of these fixes once the browsers gets updated/fixed.
 *
 * @class tinymce.pasteplugin.Quirks
 * @private
 */
define(
  'tinymce.plugins.paste.core.Quirks',
  [
    'tinymce.core.Env',
    'tinymce.core.util.Tools',
    'tinymce.plugins.paste.api.Settings',
    'tinymce.plugins.paste.core.Utils',
    'tinymce.plugins.paste.core.WordFilter'
  ],
  function (Env, Tools, Settings, Utils, WordFilter) {
    function addPreProcessFilter(editor, filterFunc) {
      editor.on('PastePreProcess', function (e) {
        e.content = filterFunc(editor, e.content, e.internal, e.wordContent);
      });
    }
    function addPostProcessFilter(editor, filterFunc) {
      editor.on('PastePostProcess', function (e) {
        filterFunc(editor, e.node);
      });
    }
    /**
     * Removes BR elements after block elements. IE9 has a nasty bug where it puts a BR element after each
     * block element when pasting from word. This removes those elements.
     *
     * This:
     *  <p>a</p><br><p>b</p>
     *
     * Becomes:
     *  <p>a</p><p>b</p>
     */
    function removeExplorerBrElementsAfterBlocks(editor, html) {
      // Only filter word specific content
      if (!WordFilter.isWordContent(html)) {
        return html;
      }
      // Produce block regexp based on the block elements in schema
      var blockElements = [];
      Tools.each(editor.schema.getBlockElements(), function (block, blockName) {
        blockElements.push(blockName);
      });
      var explorerBlocksRegExp = new RegExp(
        '(?:<br> [\\s\\r\\n]+|<br>)*(<\\/?(' + blockElements.join('|') + ')[^>]*>)(?:<br> [\\s\\r\\n]+|<br>)*',
        'g'
      );
      // Remove BR:s from: <BLOCK>X</BLOCK><BR>
      html = Utils.filter(html, [
        [explorerBlocksRegExp, '$1']
      ]);
      // IE9 also adds an extra BR element for each soft-linefeed and it also adds a BR for each word wrap break
      html = Utils.filter(html, [
        [/<br><br>/g, '<BR><BR>'], // Replace multiple BR elements with uppercase BR to keep them intact
        [/<br>/g, ' '],            // Replace single br elements with space since they are word wrap BR:s
        [/<BR><BR>/g, '<br>']      // Replace back the double brs but into a single BR
      ]);
      return html;
    }
    /**
     * WebKit has a nasty bug where the all computed styles gets added to style attributes when copy/pasting contents.
     * This fix solves that by simply removing the whole style attribute.
     *
     * The paste_webkit_styles option can be set to specify what to keep:
     *  paste_webkit_styles: "none" // Keep no styles
     *  paste_webkit_styles: "all", // Keep all of them
     *  paste_webkit_styles: "font-weight color" // Keep specific ones
     */
    function removeWebKitStyles(editor, content, internal, isWordHtml) {
      // WordFilter has already processed styles at this point and internal doesn't need any processing
      if (isWordHtml || internal) {
        return content;
      }
      // Filter away styles that isn't matching the target node
      var webKitStyles = Settings.getWebkitStyles(editor);
      if (Settings.shouldRemoveWebKitStyles(editor) === false || webKitStyles === "all") {
        return content;
      }
      if (webKitStyles) {
        webKitStyles = webKitStyles.split(/[, ]/);
      }
      // Keep specific styles that doesn't match the current node computed style
      if (webKitStyles) {
        var dom = editor.dom, node = editor.selection.getNode();
        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, function (all, before, value, after) {
          var inputStyles = dom.parseStyle(dom.decode(value), 'span');
          var outputStyles = {};
          if (webKitStyles === "none") {
            return before + after;
          }
          for (var i = 0; i < webKitStyles.length; i++) {
            var inputValue = inputStyles[webKitStyles[i]], currentValue = dom.getStyle(node, webKitStyles[i], true);
            if (/color/.test(webKitStyles[i])) {
              inputValue = dom.toHex(inputValue);
              currentValue = dom.toHex(currentValue);
            }
            if (currentValue !== inputValue) {
              outputStyles[webKitStyles[i]] = inputValue;
            }
          }
          outputStyles = dom.serializeStyle(outputStyles, 'span');
          if (outputStyles) {
            return before + ' style="' + outputStyles + '"' + after;
          }
          return before + after;
        });
      } else {
        // Remove all external styles
        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
      }
      // Keep internal styles
      content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, function (all, before, value, after) {
        return before + ' style="' + value + '"' + after;
      });
      return content;
    }
    function removeUnderlineAndFontInAnchor(editor, root) {
      editor.$('a', root).find('font,u').each(function (i, node) {
        editor.dom.remove(node, true);
      });
    }
    var setup = function (editor) {
      if (Env.webkit) {
        addPreProcessFilter(editor, removeWebKitStyles);
      }
      if (Env.ie) {
        addPreProcessFilter(editor, removeExplorerBrElementsAfterBlocks);
        addPostProcessFilter(editor, removeUnderlineAndFontInAnchor);
      }
    };
    return {
      setup: setup
    };
  }
);
 |