PHP Classes

File: public/js/tinymce/src/core/src/main/js/fmt/CaretFormat.js

Recommend this page to a friend!
  Classes of Abed Nego Ragil Putra  >  GoLavaCMS  >  public/js/tinymce/src/core/src/main/js/fmt/CaretFormat.js  >  Download  
File: public/js/tinymce/src/core/src/main/js/fmt/CaretFormat.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: GoLavaCMS
Publish content on Web pages with SEO support
Author: By
Last change:
Date: 4 years ago
Size: 11,619 bytes
 

Contents

Class file image Download
/**
 * CaretFormat.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
 */

define(
  'tinymce.core.fmt.CaretFormat',
  [
    'ephox.katamari.api.Arr',
    'ephox.sugar.api.dom.Insert',
    'ephox.sugar.api.dom.Remove',
    'ephox.sugar.api.node.Element',
    'ephox.sugar.api.node.Node',
    'ephox.sugar.api.properties.Attr',
    'tinymce.core.caret.CaretPosition',
    'tinymce.core.dom.NodeType',
    'tinymce.core.dom.PaddingBr',
    'tinymce.core.dom.TreeWalker',
    'tinymce.core.fmt.ExpandRange',
    'tinymce.core.fmt.FormatUtils',
    'tinymce.core.fmt.MatchFormat',
    'tinymce.core.selection.SplitRange',
    'tinymce.core.text.Zwsp',
    'tinymce.core.util.Fun'
  ],
  function (Arr, Insert, Remove, Element, Node, Attr, CaretPosition, NodeType, PaddingBr, TreeWalker, ExpandRange, FormatUtils, MatchFormat, SplitRange, Zwsp, Fun) {
    var ZWSP = Zwsp.ZWSP, CARET_ID = '_mce_caret';

    var importNode = function (ownerDocument, node) {
      return ownerDocument.importNode(node, true);
    };

    var isCaretNode = function (node) {
      return node.nodeType === 1 && node.id === CARET_ID;
    };

    var getEmptyCaretContainers = function (node) {
      var nodes = [];

      while (node) {
        if ((node.nodeType === 3 && node.nodeValue !== ZWSP) || node.childNodes.length > 1) {
          return [];
        }

        // Collect nodes
        if (node.nodeType === 1) {
          nodes.push(node);
        }

        node = node.firstChild;
      }

      return nodes;
    };

    var isCaretContainerEmpty = function (node) {
      return getEmptyCaretContainers(node).length > 0;
    };

    var findFirstTextNode = function (node) {
      var walker;

      if (node) {
        walker = new TreeWalker(node, node);

        for (node = walker.current(); node; node = walker.next()) {
          if (node.nodeType === 3) {
            return node;
          }
        }
      }

      return null;
    };

    var createCaretContainer = function (fill) {
      var caretContainer = Element.fromTag('span');

      Attr.setAll(caretContainer, {
        //style: 'color:red',
        id: CARET_ID,
        'data-mce-bogus': '1',
        'data-mce-type': 'format-caret'
      });

      if (fill) {
        Insert.append(caretContainer, Element.fromText(ZWSP));
      }

      return caretContainer;
    };

    var getParentCaretContainer = function (body, node) {
      while (node && node !== body) {
        if (node.id === CARET_ID) {
          return node;
        }

        node = node.parentNode;
      }

      return null;
    };

    var trimZwspFromCaretContainer = function (caretContainerNode) {
      var textNode = findFirstTextNode(caretContainerNode);
      if (textNode && textNode.nodeValue.charAt(0) === ZWSP) {
        textNode.deleteData(0, 1);
      }

      return textNode;
    };

    var removeCaretContainerNode = function (dom, selection, node, moveCaret) {
      var rng, block, textNode;

      rng = selection.getRng(true);
      block = dom.getParent(node, dom.isBlock);

      if (isCaretContainerEmpty(node)) {
        if (moveCaret !== false) {
          rng.setStartBefore(node);
          rng.setEndBefore(node);
        }

        dom.remove(node);
      } else {
        textNode = trimZwspFromCaretContainer(node);
        if (rng.startContainer === textNode && rng.startOffset > 0) {
          rng.setStart(textNode, rng.startOffset - 1);
        }

        if (rng.endContainer === textNode && rng.endOffset > 0) {
          rng.setEnd(textNode, rng.endOffset - 1);
        }

        dom.remove(node, true);
      }

      if (block && dom.isEmpty(block)) {
        PaddingBr.fillWithPaddingBr(Element.fromDom(block));
      }

      selection.setRng(rng);
    };

    // Removes the caret container for the specified node or all on the current document
    var removeCaretContainer = function (body, dom, selection, node, moveCaret) {
      if (!node) {
        node = getParentCaretContainer(body, selection.getStart());

        if (!node) {
          while ((node = dom.get(CARET_ID))) {
            removeCaretContainerNode(dom, selection, node, false);
          }
        }
      } else {
        removeCaretContainerNode(dom, selection, node, moveCaret);
      }
    };

    var insertCaretContainerNode = function (editor, caretContainer, formatNode) {
      var dom = editor.dom, block = dom.getParent(formatNode, Fun.curry(FormatUtils.isTextBlock, editor));

      if (block && dom.isEmpty(block)) {
        // Replace formatNode with caretContainer when removing format from empty block like <p><b>|</b></p>
        formatNode.parentNode.replaceChild(caretContainer, formatNode);
      } else {
        PaddingBr.removeTrailingBr(Element.fromDom(formatNode));
        if (dom.isEmpty(formatNode)) {
          formatNode.parentNode.replaceChild(caretContainer, formatNode);
        } else {
          dom.insertAfter(caretContainer, formatNode);
        }
      }
    };

    var appendNode = function (parentNode, node) {
      parentNode.appendChild(node);
      return node;
    };

    var insertFormatNodesIntoCaretContainer = function (formatNodes, caretContainer) {
      var innerMostFormatNode = Arr.foldr(formatNodes, function (parentNode, formatNode) {
        return appendNode(parentNode, formatNode.cloneNode(false));
      }, caretContainer);

      return appendNode(innerMostFormatNode, innerMostFormatNode.ownerDocument.createTextNode(ZWSP));
    };

    var applyCaretFormat = function (editor, name, vars) {
      var rng, caretContainer, textNode, offset, bookmark, container, text;
      var selection = editor.selection;

      rng = selection.getRng(true);
      offset = rng.startOffset;
      container = rng.startContainer;
      text = container.nodeValue;

      caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
      if (caretContainer) {
        textNode = findFirstTextNode(caretContainer);
      }

      // Expand to word if caret is in the middle of a text node and the char before/after is a alpha numeric character
      var wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
      if (text && offset > 0 && offset < text.length &&
        wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
        // Get bookmark of caret position
        bookmark = selection.getBookmark();

        // Collapse bookmark range (WebKit)
        rng.collapse(true);

        // Expand the range to the closest word and split it at those points
        rng = ExpandRange.expandRng(editor, rng, editor.formatter.get(name));
        rng = SplitRange.split(rng);

        // Apply the format to the range
        editor.formatter.apply(name, vars, rng);

        // Move selection back to caret position
        selection.moveToBookmark(bookmark);
      } else {
        if (!caretContainer || textNode.nodeValue !== ZWSP) {
          // Need to import the node into the document on IE or we get a lovely WrongDocument exception
          caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom());
          textNode = caretContainer.firstChild;

          rng.insertNode(caretContainer);
          offset = 1;

          editor.formatter.apply(name, vars, caretContainer);
        } else {
          editor.formatter.apply(name, vars, caretContainer);
        }

        // Move selection to text node
        selection.setCursorLocation(textNode, offset);
      }
    };

    var removeCaretFormat = function (editor, name, vars, similar) {
      var dom = editor.dom, selection = editor.selection;
      var rng = selection.getRng(true), container, offset, bookmark;
      var hasContentAfter, node, formatNode, parents = [], caretContainer;

      container = rng.startContainer;
      offset = rng.startOffset;
      node = container;

      if (container.nodeType === 3) {
        if (offset !== container.nodeValue.length) {
          hasContentAfter = true;
        }

        node = node.parentNode;
      }

      while (node) {
        if (MatchFormat.matchNode(editor, node, name, vars, similar)) {
          formatNode = node;
          break;
        }

        if (node.nextSibling) {
          hasContentAfter = true;
        }

        parents.push(node);
        node = node.parentNode;
      }

      // Node doesn't have the specified format
      if (!formatNode) {
        return;
      }

      // Is there contents after the caret then remove the format on the element
      if (hasContentAfter) {
        bookmark = selection.getBookmark();

        // Collapse bookmark range (WebKit)
        rng.collapse(true);

        // Expand the range to the closest word and split it at those points
        rng = ExpandRange.expandRng(editor, rng, editor.formatter.get(name), true);
        rng = SplitRange.split(rng);

        editor.formatter.remove(name, vars, rng);
        selection.moveToBookmark(bookmark);
      } else {
        caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
        var newCaretContainer = createCaretContainer(false).dom();
        var caretNode = insertFormatNodesIntoCaretContainer(parents, newCaretContainer);

        if (caretContainer) {
          insertCaretContainerNode(editor, newCaretContainer, caretContainer);
        } else {
          insertCaretContainerNode(editor, newCaretContainer, formatNode);
        }

        removeCaretContainerNode(dom, selection, caretContainer, false);
        selection.setCursorLocation(caretNode, 1);

        if (dom.isEmpty(formatNode)) {
          dom.remove(formatNode);
        }
      }
    };

    var disableCaretContainer = function (body, dom, selection, keyCode) {
      removeCaretContainer(body, dom, selection, null, false);

      // Remove caret container if it's empty
      if (keyCode === 8 && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
        removeCaretContainer(body, dom, selection, getParentCaretContainer(body, selection.getStart()));
      }

      // Remove caret container on keydown and it's left/right arrow keys
      if (keyCode === 37 || keyCode === 39) {
        removeCaretContainer(body, dom, selection, getParentCaretContainer(body, selection.getStart()));
      }
    };

    var setup = function (editor) {
      var dom = editor.dom, selection = editor.selection;
      var body = editor.getBody();

      editor.on('mouseup keydown', function (e) {
        disableCaretContainer(body, dom, selection, e.keyCode);
      });
    };

    var replaceWithCaretFormat = function (targetNode, formatNodes) {
      var caretContainer = createCaretContainer(false);
      var innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom());
      Insert.before(Element.fromDom(targetNode), caretContainer);
      Remove.remove(Element.fromDom(targetNode));

      return CaretPosition(innerMost, 0);
    };

    var isFormatElement = function (editor, element) {
      var inlineElements = editor.schema.getTextInlineElements();
      return inlineElements.hasOwnProperty(Node.name(element)) && !isCaretNode(element.dom()) && !NodeType.isBogus(element.dom());
    };

    return {
      setup: setup,
      applyCaretFormat: applyCaretFormat,
      removeCaretFormat: removeCaretFormat,
      isCaretNode: isCaretNode,
      getParentCaretContainer: getParentCaretContainer,
      replaceWithCaretFormat: replaceWithCaretFormat,
      isFormatElement: isFormatElement
    };
  }
);
For more information send a message to info at phpclasses dot org.