| /**
 * Utils.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 contails various utility functions for the paste plugin.
 *
 * @class tinymce.pasteplugin.Utils
 */
define(
  'tinymce.plugins.paste.core.Utils',
  [
    'global!navigator',
    'tinymce.core.html.DomParser',
    'tinymce.core.html.Schema',
    'tinymce.core.util.Tools'
  ],
  function (navigator, DomParser, Schema, Tools) {
    function filter(content, items) {
      Tools.each(items, function (v) {
        if (v.constructor === RegExp) {
          content = content.replace(v, '');
        } else {
          content = content.replace(v[0], v[1]);
        }
      });
      return content;
    }
    /**
     * Gets the innerText of the specified element. It will handle edge cases
     * and works better than textContent on Gecko.
     *
     * @param {String} html HTML string to get text from.
     * @return {String} String of text with line feeds.
     */
    function innerText(html) {
      var schema = new Schema(), domParser = new DomParser({}, schema), text = '';
      var shortEndedElements = schema.getShortEndedElements();
      var ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
      var blockElements = schema.getBlockElements();
      function walk(node) {
        var name = node.name, currentNode = node;
        if (name === 'br') {
          text += '\n';
          return;
        }
        // img/input/hr
        if (shortEndedElements[name]) {
          text += ' ';
        }
        // Ingore script, video contents
        if (ignoreElements[name]) {
          text += ' ';
          return;
        }
        if (node.type === 3) {
          text += node.value;
        }
        // Walk all children
        if (!node.shortEnded) {
          if ((node = node.firstChild)) {
            do {
              walk(node);
            } while ((node = node.next));
          }
        }
        // Add \n or \n\n for blocks or P
        if (blockElements[name] && currentNode.next) {
          text += '\n';
          if (name === 'p') {
            text += '\n';
          }
        }
      }
      html = filter(html, [
        /<!\[[^\]]+\]>/g // Conditional comments
      ]);
      walk(domParser.parse(html));
      return text;
    }
    /**
     * Trims the specified HTML by removing all WebKit fragments, all elements wrapping the body trailing BR elements etc.
     *
     * @param {String} html Html string to trim contents on.
     * @return {String} Html contents that got trimmed.
     */
    function trimHtml(html) {
      function trimSpaces(all, s1, s2) {
        // WebKit   meant to preserve multiple spaces but instead inserted around all inline tags,
        // including the spans with inline styles created on paste
        if (!s1 && !s2) {
          return ' ';
        }
        return '\u00a0';
      }
      html = filter(html, [
        /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig, // Remove anything but the contents within the BODY element
        /<!--StartFragment-->|<!--EndFragment-->/g, // Inner fragments (tables from excel on mac)
        [/( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g, trimSpaces],
        /<br class="Apple-interchange-newline">/g,
        /<br>$/i // Trailing BR elements
      ]);
      return html;
    }
    // TODO: Should be in some global class
    function createIdGenerator(prefix) {
      var count = 0;
      return function () {
        return prefix + (count++);
      };
    }
    var isMsEdge = function () {
      return navigator.userAgent.indexOf(' Edge/') !== -1;
    };
    return {
      filter: filter,
      innerText: innerText,
      trimHtml: trimHtml,
      createIdGenerator: createIdGenerator,
      isMsEdge: isMsEdge
    };
  }
);
 |