corbosman
2014-05-03 dba1c6f083de4e95b35d6dfa93b22341b6527263
program/js/tiny_mce/tiny_mce_src.js
@@ -6,18 +6,20 @@
   var tinymce = {
      majorVersion : '3',
      minorVersion : '5.2',
      minorVersion : '5.10',
      releaseDate : '2012-05-31',
      releaseDate : '2013-10-24',
      _init : function() {
         var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
         t.isIE11 = ua.indexOf('Trident/') != -1 && (ua.indexOf('rv:') != -1 || na.appName.indexOf('Netscape') != -1);
         t.isOpera = win.opera && opera.buildNumber;
         t.isWebKit = /WebKit/.test(ua);
         t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName);
         t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName) || t.isIE11;
         t.isIE6 = t.isIE && /MSIE [56]/.test(ua);
@@ -27,7 +29,7 @@
         t.isIE9 = t.isIE && /MSIE [9]/.test(ua);
         t.isGecko = !t.isWebKit && /Gecko/.test(ua);
         t.isGecko = !t.isWebKit && !t.isIE11 && /Gecko/.test(ua);
         t.isMac = ua.indexOf('Mac') != -1;
@@ -107,10 +109,14 @@
         if (!t)
            return o !== undef;
         if (t == 'array' && (o.hasOwnProperty && o instanceof Array))
         if (t == 'array' && tinymce.isArray(o))
            return true;
         return typeof(o) == t;
      },
      isArray: Array.isArray || function(obj) {
         return Object.prototype.toString.call(obj) === "[object Array]";
      },
      makeMap : function(items, delim, map) {
@@ -921,7 +927,7 @@
      }
      if (t == 'object') {
         if (o.hasOwnProperty && o instanceof Array) {
         if (o.hasOwnProperty && Object.prototype.toString.call(o) === '[object Array]') {
               for (i=0, v = '['; i<o.length; i++)
                  v += (i > 0 ? ',' : '') + serialize(o[i], quote);
@@ -1083,12 +1089,18 @@
      modifierPressed: function (e) {
         return e.shiftKey || e.ctrlKey || e.altKey;
      },
      metaKeyPressed: function(e) {
         // Check if ctrl or meta key is pressed also check if alt is false for Polish users
         return tinymce.isMac ? e.metaKey : e.ctrlKey && !e.altKey;
      }
   };
})(tinymce);
tinymce.util.Quirks = function(editor) {
   var VK = tinymce.VK, BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, settings = editor.settings;
   var VK = tinymce.VK, BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection,
      settings = editor.settings, parser = editor.parser, serializer = editor.serializer, each = tinymce.each;
   function setEditorCommandState(cmd, state) {
      try {
@@ -1098,56 +1110,87 @@
      }
   }
   function getDocumentMode() {
      var documentMode = editor.getDoc().documentMode;
      return documentMode ? documentMode : 6;
   };
   function isDefaultPrevented(e) {
      return e.isDefaultPrevented();
   };
   function cleanupStylesWhenDeleting() {
      function removeMergedFormatSpans(isDelete) {
         var rng, blockElm, node, clonedSpan;
         var rng, blockElm, wrapperElm, bookmark, container, offset, elm;
         function isAtStartOrEndOfElm() {
            if (container.nodeType == 3) {
               if (isDelete && offset == container.length) {
                  return true;
               }
               if (!isDelete && offset === 0) {
                  return true;
               }
            }
         }
         rng = selection.getRng();
         var tmpRng = [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset];
         // Find root block
         blockElm = dom.getParent(rng.startContainer, dom.isBlock);
         if (!rng.collapsed) {
            isDelete = true;
         }
         // On delete clone the root span of the next block element
         if (isDelete)
            blockElm = dom.getNext(blockElm, dom.isBlock);
         container = rng[(isDelete ? 'start' : 'end') + 'Container'];
         offset = rng[(isDelete ? 'start' : 'end') + 'Offset'];
         // Locate root span element and clone it since it would otherwise get merged by the "apple-style-span" on delete/backspace
         if (blockElm) {
            node = blockElm.firstChild;
         if (container.nodeType == 3) {
            blockElm = dom.getParent(rng.startContainer, dom.isBlock);
            // Ignore empty text nodes
            while (node && node.nodeType == 3 && node.nodeValue.length === 0)
               node = node.nextSibling;
            // On delete clone the root span of the next block element
            if (isDelete) {
               blockElm = dom.getNext(blockElm, dom.isBlock);
            }
            if (node && node.nodeName === 'SPAN') {
               clonedSpan = node.cloneNode(false);
            if (blockElm && (isAtStartOrEndOfElm() || !rng.collapsed)) {
               // Wrap children of block in a EM and let WebKit stick is
               // runtime styles junk into that EM
               wrapperElm = dom.create('em', {'id': '__mceDel'});
               each(tinymce.grep(blockElm.childNodes), function(node) {
                  wrapperElm.appendChild(node);
               });
               blockElm.appendChild(wrapperElm);
            }
         }
         // Do the backspace/delete action
         rng = dom.createRng();
         rng.setStart(tmpRng[0], tmpRng[1]);
         rng.setEnd(tmpRng[2], tmpRng[3]);
         selection.setRng(rng);
         editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
         // Find all odd apple-style-spans
         blockElm = dom.getParent(rng.startContainer, dom.isBlock);
         tinymce.each(dom.select('span.Apple-style-span,font.Apple-style-span', blockElm), function(span) {
            var bm = selection.getBookmark();
         // Remove temp wrapper element
         if (wrapperElm) {
            bookmark = selection.getBookmark();
            if (clonedSpan) {
               dom.replace(clonedSpan.cloneNode(false), span, true);
            } else {
               dom.remove(span, true);
            while (elm = dom.get('__mceDel')) {
               dom.remove(elm, true);
            }
            // Restore the selection
            selection.moveToBookmark(bm);
         });
      };
            selection.moveToBookmark(bookmark);
         }
      }
      editor.onKeyDown.add(function(editor, e) {
         var isDelete;
         isDelete = e.keyCode == DELETE;
         if (!e.isDefaultPrevented() && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
         if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
            e.preventDefault();
            removeMergedFormatSpans(isDelete);
         }
@@ -1157,74 +1200,58 @@
   };
   
   function emptyEditorWhenDeleting() {
      function getEndPointNode(rng, start) {
         var container, offset, prefix = start ? 'start' : 'end';
      function serializeRng(rng) {
         var body = dom.create("body");
         var contents = rng.cloneContents();
         body.appendChild(contents);
         return selection.serializer.serialize(body, {format: 'html'});
      }
         container = rng[prefix + 'Container'];
         offset = rng[prefix + 'Offset'];
      function allContentsSelected(rng) {
         var selection = serializeRng(rng);
         // Resolve indexed container
         if (container.nodeType == 1 && container.hasChildNodes()) {
            container = container.childNodes[Math.min(start ? offset : (offset > 0 ? offset - 1 : 0), container.childNodes.length - 1)]
         }
         var allRng = dom.createRng();
         allRng.selectNode(editor.getBody());
         return container;
      };
         var allSelection = serializeRng(allRng);
         return selection === allSelection;
      }
      function isAtStartEndOfBody(rng, start) {
         var container, offset, root, childNode, prefix = start ? 'start' : 'end', isAfter;
      editor.onKeyDown.add(function(editor, e) {
         var keyCode = e.keyCode, isCollapsed;
         container = rng[prefix + 'Container'];
         offset = rng[prefix + 'Offset'];
         root = dom.getRoot();
         // Empty the editor if it's needed for example backspace at <p><b>|</b></p>
         if (!isDefaultPrevented(e) && (keyCode == DELETE || keyCode == BACKSPACE)) {
            isCollapsed = editor.selection.isCollapsed();
         // Resolve indexed container
         if (container.nodeType == 1) {
            isAfter = offset >= container.childNodes.length;
            container = getEndPointNode(rng, start);
            if (container.nodeType == 3) {
               offset = start && !isAfter ? 0 : container.nodeValue.length;
            }
         }
         // Check if start/end is in the middle of text
         if (container.nodeType == 3 && ((start && offset > 0) || (!start && offset < container.nodeValue.length))) {
            return false;
         }
         // Walk up the DOM tree to see if the endpoint is at the beginning/end of body
         while (container !== root) {
            childNode = container.parentNode[start ? 'firstChild' : 'lastChild'];
            // If first/last element is a BR then jump to it's sibling in case: <p>x<br></p>
            if (childNode.nodeName == "BR") {
               childNode = childNode[start ? 'nextSibling' : 'previousSibling'] || childNode;
            // Selection is collapsed but the editor isn't empty
            if (isCollapsed && !dom.isEmpty(editor.getBody())) {
               return;
            }
            // If the childNode isn't the container node then break in case <p><span>A</span>[X]</p>
            if (childNode !== container) {
               return false;
            // IE deletes all contents correctly when everything is selected
            if (tinymce.isIE && !isCollapsed) {
               return;
            }
            container = container.parentNode;
            // Selection isn't collapsed but not all the contents is selected
            if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
               return;
            }
            // Manually empty the editor
            editor.setContent('');
            editor.selection.setCursorLocation(editor.getBody(), 0);
            editor.nodeChanged();
         }
      });
   };
         return true;
      };
      editor.onKeyDown.addToTop(function(editor, e) {
         var rng, keyCode = e.keyCode;
         if (!e.isDefaultPrevented() && (keyCode == DELETE || keyCode == BACKSPACE)) {
            rng = selection.getRng(true);
            if (isAtStartEndOfBody(rng, true) && isAtStartEndOfBody(rng, false) &&
               (rng.collapsed || dom.findCommonAncestor(getEndPointNode(rng, true), getEndPointNode(rng)) === dom.getRoot())) {
               editor.setContent('');
               editor.nodeChanged();
               e.preventDefault();
            }
   function selectAll() {
      editor.onKeyDown.add(function(editor, e) {
         if (!isDefaultPrevented(e) && e.keyCode == 65 && VK.metaKeyPressed(e)) {
            e.preventDefault();
            editor.execCommand('SelectAll');
         }
      });
   };
@@ -1248,7 +1275,7 @@
   function removeHrOnBackspace() {
      editor.onKeyDown.add(function(editor, e) {
         if (!e.isDefaultPrevented() && e.keyCode === BACKSPACE) {
         if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
            if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
               var node = selection.getNode();
               var previousSibling = node.previousSibling;
@@ -1267,7 +1294,7 @@
      // wouldn't get proper focus if the user clicked on the HTML element
      if (!Range.prototype.getClientRects) { // Detect getClientRects got introduced in FF 4
         editor.onMouseDown.add(function(editor, e) {
            if (e.target.nodeName === "HTML") {
            if (!isDefaultPrevented(e) && e.target.nodeName === "HTML") {
               var body = editor.getBody();
               // Blur the body it's focused but not correctly focused
@@ -1311,7 +1338,7 @@
            if (target !== editor.getBody()) {
               dom.setAttrib(target, "style", null);
               tinymce.each(template, function(attr) {
               each(template, function(attr) {
                  target.setAttributeNode(attr.cloneNode(true));
               });
            }
@@ -1319,7 +1346,7 @@
      }
      function isSelectionAcrossElements() {
         return !selection.isCollapsed() && selection.getStart() != selection.getEnd();
         return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) != dom.getParent(selection.getEnd(), dom.isBlock);
      }
      function blockEvent(editor, e) {
@@ -1330,7 +1357,7 @@
      editor.onKeyPress.add(function(editor, e) {
         var applyAttributes;
         if ((e.keyCode == 8 || e.keyCode == 46) && isSelectionAcrossElements()) {
         if (!isDefaultPrevented(e) && (e.keyCode == 8 || e.keyCode == 46) && isSelectionAcrossElements()) {
            applyAttributes = getAttributeApplyFunction();
            editor.getDoc().execCommand('delete', false, null);
            applyAttributes();
@@ -1342,7 +1369,7 @@
      dom.bind(editor.getDoc(), 'cut', function(e) {
         var applyAttributes;
         if (isSelectionAcrossElements()) {
         if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
            applyAttributes = getAttributeApplyFunction();
            editor.onKeyUp.addToTop(blockEvent);
@@ -1381,7 +1408,7 @@
   function disableBackspaceIntoATable() {
      editor.onKeyDown.add(function(editor, e) {
         if (!e.isDefaultPrevented() && e.keyCode === BACKSPACE) {
         if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
            if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
               var previousSibling = selection.getNode().previousSibling;
               if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "table") {
@@ -1393,20 +1420,19 @@
   }
   function addNewLinesBeforeBrInPre() {
      var documentMode = editor.getDoc().documentMode;
      // IE8+ rendering mode does the right thing with BR in PRE
      if (documentMode && documentMode > 7) {
      if (getDocumentMode() > 7) {
         return;
      }
       // Enable display: none in area and add a specific class that hides all BR elements in PRE to
       // avoid the caret from getting stuck at the BR elements while pressing the right arrow key
      setEditorCommandState('RespectVisibilityInDesign', true);
      editor.contentStyles.push('.mceHideBrInPre pre br {display: none}');
      dom.addClass(editor.getBody(), 'mceHideBrInPre');
      // Adds a \n before all BR elements in PRE to get them visual
      editor.parser.addNodeFilter('pre', function(nodes, name) {
      parser.addNodeFilter('pre', function(nodes, name) {
         var i = nodes.length, brNodes, j, brElm, sibling;
         while (i--) {
@@ -1427,7 +1453,7 @@
      });
      // Removes any \n before BR elements in PRE since other browsers and in contentEditable=false mode they will be visible
      editor.serializer.addNodeFilter('pre', function(nodes, name) {
      serializer.addNodeFilter('pre', function(nodes, name) {
         var i = nodes.length, brNodes, j, brElm, sibling;
         while (i--) {
@@ -1470,7 +1496,7 @@
         var isDelete, rng, container, offset, brElm, sibling, collapsed;
         isDelete = e.keyCode == DELETE;
         if (!e.isDefaultPrevented() && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
         if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
            rng = selection.getRng();
            container = rng.startContainer;
            offset = rng.startOffset;
@@ -1479,6 +1505,12 @@
            // Override delete if the start container is a text node and is at the beginning of text or
            // just before/after the last character to be deleted in collapsed mode
            if (container.nodeType == 3 && container.nodeValue.length > 0 && ((offset === 0 && !collapsed) || (collapsed && offset === (isDelete ? 0 : 1)))) {
               // Edge case when deleting <p><b><img> |x</b></p>
               sibling = container.previousSibling;
               if (sibling && sibling.nodeName == "IMG") {
                  return;
               }
               nonEmptyElements = editor.schema.getNonEmptyElements();
               // Prevent default logic since it's broken
@@ -1510,7 +1542,7 @@
      editor.onKeyDown.add(function(editor, e) {
         var rng, container, offset, root, parent;
         if (e.isDefaultPrevented() || e.keyCode != VK.BACKSPACE) {
         if (isDefaultPrevented(e) || e.keyCode != VK.BACKSPACE) {
            return;
         }
@@ -1534,10 +1566,10 @@
            editor.formatter.toggle('blockquote', null, parent);
            // Move the caret to the beginning of container
            rng = dom.createRng();
            rng.setStart(container, 0);
            rng.setEnd(container, 0);
            selection.setRng(rng);
            selection.collapse(false);
         }
      });
   };
@@ -1562,7 +1594,7 @@
   function addBrAfterLastLinks() {
      function fixLinks(editor, o) {
         tinymce.each(dom.select('a'), function(node) {
         each(dom.select('a'), function(node) {
            var parentNode = node.parentNode, root = dom.getRoot();
            if (parentNode.lastChild === node) {
@@ -1608,16 +1640,319 @@
      editor.onSetContent.add(repaint);
   };
   function deleteImageOnBackSpace() {
   function deleteControlItemOnBackSpace() {
      editor.onKeyDown.add(function(editor, e) {
         if (!e.isDefaultPrevented() && e.keyCode == 8 && selection.getNode().nodeName == 'IMG') {
            e.preventDefault();
            editor.undoManager.beforeChange();
            dom.remove(selection.getNode());
            editor.undoManager.add();
         var rng;
         if (!isDefaultPrevented(e) && e.keyCode == BACKSPACE) {
            rng = editor.getDoc().selection.createRange();
            if (rng && rng.item) {
               e.preventDefault();
               editor.undoManager.beforeChange();
               dom.remove(rng.item(0));
               editor.undoManager.add();
            }
         }
      });
   };
   function renderEmptyBlocksFix() {
      var emptyBlocksCSS;
      // IE10+
      if (getDocumentMode() >= 10) {
         emptyBlocksCSS = '';
         each('p div h1 h2 h3 h4 h5 h6'.split(' '), function(name, i) {
            emptyBlocksCSS += (i > 0 ? ',' : '') + name + ':empty';
         });
         editor.contentStyles.push(emptyBlocksCSS + '{padding-right: 1px !important}');
      }
   };
   function fakeImageResize() {
      var selectedElmX, selectedElmY, selectedElm, selectedElmGhost, selectedHandle, startX, startY, startW, startH, ratio,
         resizeHandles, width, height, rootDocument = document, editableDoc = editor.getDoc();
      if (!settings.object_resizing || settings.webkit_fake_resize === false) {
         return;
      }
      // Try disabling object resizing if WebKit implements resizing in the future
      setEditorCommandState("enableObjectResizing", false);
      // Details about each resize handle how to scale etc
      resizeHandles = {
         // Name: x multiplier, y multiplier, delta size x, delta size y
         n: [.5, 0, 0, -1],
         e: [1, .5, 1, 0],
         s: [.5, 1, 0, 1],
         w: [0, .5, -1, 0],
         nw: [0, 0, -1, -1],
         ne: [1, 0, 1, -1],
         se: [1, 1, 1, 1],
         sw : [0, 1, -1, 1]
      };
      function resizeElement(e) {
         var deltaX, deltaY;
         // Calc new width/height
         deltaX = e.screenX - startX;
         deltaY = e.screenY - startY;
         // Calc new size
         width = deltaX * selectedHandle[2] + startW;
         height = deltaY * selectedHandle[3] + startH;
         // Never scale down lower than 5 pixels
         width = width < 5 ? 5 : width;
         height = height < 5 ? 5 : height;
         // Constrain proportions when modifier key is pressed or if the nw, ne, sw, se corners are moved on an image
         if (VK.modifierPressed(e) || (selectedElm.nodeName == "IMG" && selectedHandle[2] * selectedHandle[3] !== 0)) {
            width = Math.round(height / ratio);
            height = Math.round(width * ratio);
         }
         // Update ghost size
         dom.setStyles(selectedElmGhost, {
            width: width,
            height: height
         });
         // Update ghost X position if needed
         if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
            dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width));
         }
         // Update ghost Y position if needed
         if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
            dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height));
         }
      }
      function endResize() {
         function setSizeProp(name, value) {
            if (value) {
               // Resize by using style or attribute
               if (selectedElm.style[name] || !editor.schema.isValid(selectedElm.nodeName.toLowerCase(), name)) {
                  dom.setStyle(selectedElm, name, value);
               } else {
                  dom.setAttrib(selectedElm, name, value);
               }
            }
         }
         // Set width/height properties
         setSizeProp('width', width);
         setSizeProp('height', height);
         dom.unbind(editableDoc, 'mousemove', resizeElement);
         dom.unbind(editableDoc, 'mouseup', endResize);
         if (rootDocument != editableDoc) {
            dom.unbind(rootDocument, 'mousemove', resizeElement);
            dom.unbind(rootDocument, 'mouseup', endResize);
         }
         // Remove ghost and update resize handle positions
         dom.remove(selectedElmGhost);
         showResizeRect(selectedElm);
      }
      function showResizeRect(targetElm) {
         var position, targetWidth, targetHeight;
         hideResizeRect();
         // Get position and size of target
         position = dom.getPos(targetElm);
         selectedElmX = position.x;
         selectedElmY = position.y;
         targetWidth = targetElm.offsetWidth;
         targetHeight = targetElm.offsetHeight;
         // Reset width/height if user selects a new image/table
         if (selectedElm != targetElm) {
            selectedElm = targetElm;
            width = height = 0;
         }
         each(resizeHandles, function(handle, name) {
            var handleElm;
            // Get existing or render resize handle
            handleElm = dom.get('mceResizeHandle' + name);
            if (!handleElm) {
               handleElm = dom.add(editableDoc.documentElement, 'div', {
                  id: 'mceResizeHandle' + name,
                  'class': 'mceResizeHandle',
                  style: 'cursor:' + name + '-resize; margin:0; padding:0'
               });
               dom.bind(handleElm, 'mousedown', function(e) {
                  e.preventDefault();
                  endResize();
                  startX = e.screenX;
                  startY = e.screenY;
                  startW = selectedElm.clientWidth;
                  startH = selectedElm.clientHeight;
                  ratio = startH / startW;
                  selectedHandle = handle;
                  selectedElmGhost = selectedElm.cloneNode(true);
                  dom.addClass(selectedElmGhost, 'mceClonedResizable');
                  dom.setStyles(selectedElmGhost, {
                     left: selectedElmX,
                     top: selectedElmY,
                     margin: 0
                  });
                  editableDoc.documentElement.appendChild(selectedElmGhost);
                  dom.bind(editableDoc, 'mousemove', resizeElement);
                  dom.bind(editableDoc, 'mouseup', endResize);
                  if (rootDocument != editableDoc) {
                     dom.bind(rootDocument, 'mousemove', resizeElement);
                     dom.bind(rootDocument, 'mouseup', endResize);
                  }
               });
            } else {
               dom.show(handleElm);
            }
            // Position element
            dom.setStyles(handleElm, {
               left: (targetWidth * handle[0] + selectedElmX) - (handleElm.offsetWidth / 2),
               top: (targetHeight * handle[1] + selectedElmY) - (handleElm.offsetHeight / 2)
            });
         });
         // Only add resize rectangle on WebKit and only on images
         if (!tinymce.isOpera && selectedElm.nodeName == "IMG") {
            selectedElm.setAttribute('data-mce-selected', '1');
         }
      }
      function hideResizeRect() {
         if (selectedElm) {
            selectedElm.removeAttribute('data-mce-selected');
         }
         for (var name in resizeHandles) {
            dom.hide('mceResizeHandle' + name);
         }
      }
      // Add CSS for resize handles, cloned element and selected
      editor.contentStyles.push(
         '.mceResizeHandle {' +
            'position: absolute;' +
            'border: 1px solid black;' +
            'background: #FFF;' +
            'width: 5px;' +
            'height: 5px;' +
            'z-index: 10000' +
         '}' +
         '.mceResizeHandle:hover {' +
            'background: #000' +
         '}' +
         'img[data-mce-selected] {' +
            'outline: 1px solid black' +
         '}' +
         'img.mceClonedResizable, table.mceClonedResizable {' +
            'position: absolute;' +
            'outline: 1px dashed black;' +
            'opacity: .5;' +
            'z-index: 10000' +
         '}'
      );
      function updateResizeRect() {
         var controlElm = dom.getParent(selection.getNode(), 'table,img');
         // Remove data-mce-selected from all elements since they might have been copied using Ctrl+c/v
         each(dom.select('img[data-mce-selected]'), function(img) {
            img.removeAttribute('data-mce-selected');
         });
         if (controlElm) {
            showResizeRect(controlElm);
         } else {
            hideResizeRect();
         }
      }
      // Show/hide resize rect when image is selected
      editor.onNodeChange.add(updateResizeRect);
      // Fixes WebKit quirk where it returns IMG on getNode if caret is after last image in container
      dom.bind(editableDoc, 'selectionchange', updateResizeRect);
      // Remove the internal attribute when serializing the DOM
      editor.serializer.addAttributeFilter('data-mce-selected', function(nodes, name) {
         var i = nodes.length;
         while (i--) {
            nodes[i].attr(name, null);
         }
      });
   }
   function keepNoScriptContents() {
      if (getDocumentMode() < 9) {
         parser.addNodeFilter('noscript', function(nodes) {
            var i = nodes.length, node, textNode;
            while (i--) {
               node = nodes[i];
               textNode = node.firstChild;
               if (textNode) {
                  node.attr('data-mce-innertext', textNode.value);
               }
            }
         });
         serializer.addNodeFilter('noscript', function(nodes) {
            var i = nodes.length, node, textNode, value;
            while (i--) {
               node = nodes[i];
               textNode = nodes[i].firstChild;
               if (textNode) {
                  textNode.value = tinymce.html.Entities.decode(textNode.value);
               } else {
                  // Old IE can't retain noscript value so an attribute is used to store it
                  value = node.attributes.map['data-mce-innertext'];
                  if (value) {
                     node.attr('data-mce-innertext', null);
                     textNode = new tinymce.html.Node('#text', 3);
                     textNode.value = value;
                     textNode.raw = true;
                     node.append(textNode);
                  }
               }
            }
         });
      }
   }
   function bodyHeight() {
      editor.contentStyles.push('body {min-height: 100px}');
      editor.onClick.add(function(ed, e) {
         if (e.target.nodeName == 'HTML') {
            editor.execCommand('SelectAll');
            editor.selection.collapse(true);
            editor.nodeChanged();
         }
      });
   }
   // All browsers
   disableBackspaceIntoATable();
@@ -1635,26 +1970,41 @@
      // iOS
      if (tinymce.isIDevice) {
         selectionChangeNodeChanged();
      } else {
         fakeImageResize();
         selectAll();
      }
   }
   // IE
   if (tinymce.isIE) {
   if (tinymce.isIE && !tinymce.isIE11) {
      removeHrOnBackspace();
      ensureBodyHasRoleApplication();
      addNewLinesBeforeBrInPre();
      removePreSerializedStylesWhenSelectingControls();
      deleteImageOnBackSpace();
      deleteControlItemOnBackSpace();
      renderEmptyBlocksFix();
      keepNoScriptContents();
   }
   // IE 11+
   if (tinymce.isIE11) {
      bodyHeight();
   }
   // Gecko
   if (tinymce.isGecko) {
   if (tinymce.isGecko && !tinymce.isIE11) {
      removeHrOnBackspace();
      focusBody();
      removeStylesWhenDeletingAccrossBlockElements();
      setGeckoEditingOptions();
      addBrAfterLastLinks();
      removeGhostSelection();
   }
   // Opera
   if (tinymce.isOpera) {
      fakeImageResize();
   }
};
(function(tinymce) {
@@ -1879,6 +2229,12 @@
         function compress(prefix, suffix) {
            var top, right, bottom, left;
            // IE 11 will produce a border-image: none when getting the style attribute from <p style="border: 1px solid red"></p>
            // So lets asume it shouldn't be there
            if (styles['border-image'] === 'none') {
               delete styles['border-image'];
            }
            // Get values and check it it needs compressing
            top = styles[prefix + '-top' + suffix];
@@ -2107,9 +2463,9 @@
      if (!html5) {
         html5 = mapCache.html5 = unpack({
               A : 'id|accesskey|class|dir|draggable|item|hidden|itemprop|role|spellcheck|style|subject|title',
               A : 'id|accesskey|class|dir|draggable|item|hidden|itemprop|role|spellcheck|style|subject|title|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup',
               B : '#|a|abbr|area|audio|b|bdo|br|button|canvas|cite|code|command|datalist|del|dfn|em|embed|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|meta|' +
                  'meter|noscript|object|output|progress|q|ruby|samp|script|select|small|span|strong|sub|sup|svg|textarea|time|var|video',
                  'meter|noscript|object|output|progress|q|ruby|samp|script|select|small|span|strong|sub|sup|svg|textarea|time|var|video|wbr',
               C : '#|a|abbr|area|address|article|aside|audio|b|bdo|blockquote|br|button|canvas|cite|code|command|datalist|del|details|dfn|dialog|div|dl|em|embed|fieldset|' +
                  'figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|menu|meta|meter|nav|noscript|ol|object|output|' +
                  'p|pre|progress|q|ruby|samp|script|section|select|small|span|strong|style|sub|sup|svg|table|textarea|time|ul|var|video'
@@ -2194,7 +2550,7 @@
               'form[A|accept-charset|action|autocomplete|enctype|method|name|novalidate|target][C]' +
               'fieldset[A|disabled|form|name][C|legend]' +
               'label[A|form|for][B]' +
               'input[A|type|accept|alt|autocomplete|checked|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|list|max|maxlength|min|' +
               'input[A|type|accept|alt|autocomplete|autofocus|checked|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|list|max|maxlength|min|' +
                  'multiple|pattern|placeholder|readonly|required|size|src|step|width|files|value|name][]' +
               'button[A|autofocus|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|name|value|type][B]' +
               'select[A|autofocus|disabled|form|multiple|name|size][option|optgroup]' +
@@ -2218,7 +2574,8 @@
               'tbody[A][tr]' +
               'tr[A][th|td]' +
               'th[A|headers|rowspan|colspan|scope][B]' +
               'td[A|headers|rowspan|colspan][C]'
               'td[A|headers|rowspan|colspan][C]' +
               'wbr[A][]'
         );
      }
@@ -2397,14 +2754,15 @@
      }
      // Setup map objects
      whiteSpaceElementsMap = createLookupTable('whitespace_elements', 'pre script style textarea');
      whiteSpaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea');
      selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
      shortEndedElementsMap = createLookupTable('short_ended_elements', 'area base basefont br col frame hr img input isindex link meta param embed source');
      shortEndedElementsMap = createLookupTable('short_ended_elements', 'area base basefont br col frame hr img input isindex link meta param embed source wbr');
      boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls');
      nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object', shortEndedElementsMap);
      blockElementsMap = createLookupTable('block_elements', 'h1 h2 h3 h4 h5 h6 hr p div address pre form table tbody thead tfoot ' +
                  'th tr td li ol ul caption blockquote center dl dt dd dir fieldset ' +
                  'noscript menu isindex samp header footer article section hgroup aside nav figure option datalist select optgroup');
      nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object script', shortEndedElementsMap);
      textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' +
                  'blockquote center dir fieldset header footer article section hgroup aside nav figure');
      blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' +
                  'th tr td li ol ul caption dl dt dd noscript menu isindex samp option datalist select optgroup', textBlockElementsMap);
      // Converts a wildcard expression string to a regexp for example *a will become /.*a/.
      function patternToRegExp(str) {
@@ -2578,8 +2936,15 @@
               customElementsMap[name] = cloneName;
               // If it's not marked as inline then add it to valid block elements
               if (!inline)
               if (!inline) {
                  blockElementsMap[name.toUpperCase()] = {};
                  blockElementsMap[name] = {};
               }
               // Add elements clone if needed
               if (!elements[name]) {
                  elements[name] = elements[cloneName];
               }
               // Add custom elements at span/div positions
               each(children, function(element, child) {
@@ -2704,6 +3069,10 @@
         return blockElementsMap;
      };
      self.getTextBlockElements = function() {
         return textBlockElementsMap;
      };
      self.getShortEndedElements = function() {
         return shortEndedElementsMap;
      };
@@ -2769,6 +3138,8 @@
      self.addCustomElements = addCustomElements;
      self.addValidChildren = addValidChildren;
      self.elements = elements;
   };
})(tinymce);
@@ -2867,10 +3238,10 @@
            '(?:!DOCTYPE([\\w\\W]*?)>)|' + // DOCTYPE
            '(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|' + // PI
            '(?:\\/([^>]+)>)|' + // End element
            '(?:([A-Za-z0-9\\-\\:]+)((?:\\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\\/|\\s+)>)' + // Start element
            '(?:([A-Za-z0-9\\-\\:\\.]+)((?:\\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\\/|\\s+)>)' + // Start element
         ')', 'g');
         attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:\\.|[^\"])*)\")|(?:\'((?:\\.|[^\'])*)\')|([^>\s]+)))?/g;
         attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g;
         specialElements = {
            'script' : /<\/script[^>]*>/gi,
            'style' : /<\/style[^>]*>/gi,
@@ -3353,7 +3724,7 @@
                  i = node.attributes.length;
                  while (i--) {
                     name = node.attributes[i].name;
                     if (name === "name" || name.indexOf('data-') === 0)
                     if (name === "name" || name.indexOf('data-mce-') === 0)
                        return false;
                  }
               }
@@ -3409,17 +3780,40 @@
      function fixInvalidChildren(nodes) {
         var ni, node, parent, parents, newParent, currentNode, tempNode, childNode, i,
            childClone, nonEmptyElements, nonSplitableElements, sibling, nextNode;
            childClone, nonEmptyElements, nonSplitableElements, textBlockElements, sibling, nextNode;
         nonSplitableElements = tinymce.makeMap('tr,td,th,tbody,thead,tfoot,table');
         nonEmptyElements = schema.getNonEmptyElements();
         textBlockElements = schema.getTextBlockElements();
         for (ni = 0; ni < nodes.length; ni++) {
            node = nodes[ni];
            // Already removed
            if (!node.parent)
            // Already removed or fixed
            if (!node.parent || node.fixed)
               continue;
            // If the invalid element is a text block and the text block is within a parent LI element
            // Then unwrap the first text block and convert other sibling text blocks to LI elements similar to Word/Open Office
            if (textBlockElements[node.name] && node.parent.name == 'li') {
               // Move sibling text blocks after LI element
               sibling = node.next;
               while (sibling) {
                  if (textBlockElements[sibling.name]) {
                     sibling.name = 'li';
                     sibling.fixed = true;
                     node.parent.insert(sibling, node.parent);
                  } else {
                     break;
                  }
                  sibling = sibling.next;
               }
               // Unwrap current text block
               node.unwrap(node);
               continue;
            }
            // Get list of all parent nodes until we find a valid parent to stick the child into
            parents = [node];
@@ -3798,7 +4192,8 @@
                     }
                     // Trim start white space
                     textNode = node.prev;
                     // Removed due to: #5424
                     /*textNode = node.prev;
                     if (textNode && textNode.type === 3) {
                        text = textNode.value.replace(startWhiteSpaceRegExp, '');
@@ -3806,7 +4201,7 @@
                           textNode.value = text;
                        else
                           textNode.remove();
                     }
                     }*/
                  }
                  // Check if we exited a whitespace preserved element
@@ -4316,6 +4711,12 @@
         }
      }
      // Page already loaded then fire it directly
      if (doc.readyState == "complete") {
         readyHandler();
         return;
      }
      // Use W3C method
      if (w3cEventModel) {
         addEvent(win, 'DOMContentLoaded', readyHandler);
@@ -4657,7 +5058,7 @@
         // Old API supported multiple targets
         if (target && target instanceof Array) {
            var i = target;
            var i = target.length;
            while (i--) {
               self.add(target[i], events, func, scope);
@@ -4859,6 +5260,11 @@
         blockElementsMap = s.schema ? s.schema.getBlockElements() : {};
         t.isBlock = function(node) {
            // Fix for #5446
            if (!node) {
               return false;
            }
            // This function is called in module pattern style since it might be executed with the wrong this scope
            var type = node.nodeType;
@@ -4873,7 +5279,7 @@
      fixDoc: function(doc) {
         var settings = this.settings, name;
         if (isIE && settings.schema) {
         if (isIE && !tinymce.isIE11 && settings.schema) {
            // Add missing HTML 4/5 elements to IE
            ('abbr article aside audio canvas ' +
            'details figcaption figure footer ' +
@@ -4894,7 +5300,7 @@
         var self = this, clone, doc;
         // TODO: Add feature detection here in the future
         if (!isIE || node.nodeType !== 1 || deep) {
         if (!isIE || tinymce.isIE11 || node.nodeType !== 1 || deep) {
            return node.cloneNode(deep);
         }
@@ -5167,7 +5573,7 @@
            switch (na) {
               case 'opacity':
                  // IE specific opacity
                  if (isIE) {
                  if (isIE && ! tinymce.isIE11) {
                     s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")";
                     if (!n.currentStyle || !n.currentStyle.hasLayout)
@@ -5179,7 +5585,7 @@
                  break;
               case 'float':
                  isIE ? s.styleFloat = v : s.cssFloat = v;
                  (isIE && ! tinymce.isIE11) ? s.styleFloat = v : s.cssFloat = v;
                  break;
               
               default:
@@ -5499,6 +5905,32 @@
         return this.styles.serialize(o, name);
      },
      addStyle: function(cssText) {
         var doc = this.doc, head;
         // Create style element if needed
         styleElm = doc.getElementById('mceDefaultStyles');
         if (!styleElm) {
            styleElm = doc.createElement('style'),
            styleElm.id = 'mceDefaultStyles';
            styleElm.type = 'text/css';
            head = doc.getElementsByTagName('head')[0];
            if (head.firstChild) {
               head.insertBefore(styleElm, head.firstChild);
            } else {
               head.appendChild(styleElm);
            }
         }
         // Append style data to old or new style element
         if (styleElm.styleSheet) {
            styleElm.styleSheet.cssText += cssText;
         } else {
            styleElm.appendChild(doc.createTextNode(cssText));
         }
      },
      loadCSS : function(u) {
         var t = this, d = t.doc, head;
@@ -5519,7 +5951,7 @@
            // IE 8 has a bug where dynamically loading stylesheets would produce a 1 item remaining bug
            // This fix seems to resolve that issue by realcing the document ones a stylesheet finishes loading
            // It's ugly but it seems to work fine.
            if (isIE && d.documentMode && d.recalc) {
            if (isIE && !tinymce.isIE11 && d.documentMode && d.recalc) {
               link.onload = function() {
                  if (d.recalc)
                     d.recalc();
@@ -5622,13 +6054,13 @@
                  // This seems to fix this problem
                  // Create new div with HTML contents and a BR infront to keep comments
                  element = self.create('div');
                  element.innerHTML = '<br />' + html;
                  var newElement = self.create('div');
                  newElement.innerHTML = '<br />' + html;
                  // Add all children from div to target
                  each (element.childNodes, function(node, i) {
                  each (tinymce.grep(newElement.childNodes), function(node, i) {
                     // Skip br element
                     if (i)
                     if (i && element.canHaveHTML)
                        element.appendChild(node);
                  });
               }
@@ -5838,7 +6270,12 @@
                  // Import
                  case 3:
                     addClasses(r.styleSheet);
                     try {
                        addClasses(r.styleSheet);
                     } catch (ex) {
                        // Ignore
                     }
                     break;
               }
            });
@@ -7233,7 +7670,8 @@
      };
      this.addRange = function(rng) {
         var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, sibling, doc = selection.dom.doc, body = doc.body;
         var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, sibling,
            doc = selection.dom.doc, body = doc.body, nativeRng, ctrlElm;
         function setEndPoint(start) {
            var container, offset, marker, tmpRng, nodes;
@@ -7319,10 +7757,17 @@
            if (startOffset == endOffset - 1) {
               try {
                  ctrlElm = startContainer.childNodes[startOffset];
                  ctrlRng = body.createControlRange();
                  ctrlRng.addElement(startContainer.childNodes[startOffset]);
                  ctrlRng.addElement(ctrlElm);
                  ctrlRng.select();
                  return;
                  // Check if the range produced is on the correct element and is a control range
                  // On IE 8 it will select the parent contentEditable container if you select an inner element see: #5398
                  nativeRng = selection.getRng();
                  if (nativeRng.item && ctrlElm === nativeRng.item(0)) {
                     return;
                  }
               } catch (ex) {
                  // Ignore
               }
@@ -8932,7 +9377,7 @@
         if (!t.win.getSelection)
            t.tridentSel = new tinymce.dom.TridentSelection(t);
         if (tinymce.isIE && dom.boxModel)
         if (tinymce.isIE && ! tinymce.isIE11 && dom.boxModel)
            this._fixIESelection();
         // Prevent leaks
@@ -9069,7 +9514,7 @@
      },
      getStart : function() {
         var rng = this.getRng(), startElement, parentElement, checkRng, node;
         var self = this, rng = self.getRng(), startElement, parentElement, checkRng, node;
         if (rng.duplicate || rng.item) {
            // Control selection, return first item
@@ -9080,6 +9525,9 @@
            checkRng = rng.duplicate();
            checkRng.collapse(1);
            startElement = checkRng.parentElement();
            if (startElement.ownerDocument !== self.dom.doc) {
               startElement = self.dom.getRoot();
            }
            // Check if range parent is inside the start element, then return the inner parent element
            // This will fix issues when a single element is selected, IE would otherwise return the wrong start element
@@ -9106,31 +9554,34 @@
      },
      getEnd : function() {
         var t = this, r = t.getRng(), e, eo;
         var self = this, rng = self.getRng(), endElement, endOffset;
         if (r.duplicate || r.item) {
            if (r.item)
               return r.item(0);
         if (rng.duplicate || rng.item) {
            if (rng.item)
               return rng.item(0);
            r = r.duplicate();
            r.collapse(0);
            e = r.parentElement();
            rng = rng.duplicate();
            rng.collapse(0);
            endElement = rng.parentElement();
            if (endElement.ownerDocument !== self.dom.doc) {
               endElement = self.dom.getRoot();
            }
            if (e && e.nodeName == 'BODY')
               return e.lastChild || e;
            if (endElement && endElement.nodeName == 'BODY')
               return endElement.lastChild || endElement;
            return e;
            return endElement;
         } else {
            e = r.endContainer;
            eo = r.endOffset;
            endElement = rng.endContainer;
            endOffset = rng.endOffset;
            if (e.nodeType == 1 && e.hasChildNodes())
               e = e.childNodes[eo > 0 ? eo - 1 : eo];
            if (endElement.nodeType == 1 && endElement.hasChildNodes())
               endElement = endElement.childNodes[endOffset > 0 ? endOffset - 1 : endOffset];
            if (e && e.nodeType == 3)
               return e.parentNode;
            if (endElement && endElement.nodeType == 3)
               return endElement.parentNode;
            return e;
            return endElement;
         }
      },
@@ -9218,8 +9669,20 @@
         }
         // Handle simple range
         if (type)
            return {rng : t.getRng()};
         if (type) {
            rng = t.getRng();
            if (rng.setStart) {
               rng = {
                  startContainer: rng.startContainer,
                  startOffset: rng.startOffset,
                  endContainer: rng.endContainer,
                  endOffset: rng.endOffset
               };
            }
            return {rng : rng};
         }
         rng = t.getRng();
         id = dom.uniqueId();
@@ -9285,7 +9748,7 @@
      },
      moveToBookmark : function(bookmark) {
         var t = this, dom = t.dom, marker1, marker2, rng, root, startContainer, endContainer, startOffset, endOffset;
         var t = this, dom = t.dom, marker1, marker2, rng, rng2, root, startContainer, endContainer, startOffset, endOffset;
         function setEndPoint(start) {
            var point = bookmark[start ? 'start' : 'end'], i, node, offset, children;
@@ -9415,8 +9878,24 @@
               }
            } else if (bookmark.name) {
               t.select(dom.select(bookmark.name)[bookmark.index]);
            } else if (bookmark.rng)
               t.setRng(bookmark.rng);
            } else if (bookmark.rng) {
               rng = bookmark.rng;
               if (rng.startContainer) {
                  rng2 = t.dom.createRng();
                  try {
                     rng2.setStart(rng.startContainer, rng.startOffset);
                     rng2.setEnd(rng.endContainer, rng.endOffset);
                  } catch (e) {
                     // Might fail with index error
                  }
                  rng = rng2;
               }
               t.setRng(rng);
            }
         }
      },
@@ -9515,7 +9994,7 @@
         }
         // We have W3C ranges and it's IE then fake control selection since IE9 doesn't handle that correctly yet
         if (tinymce.isIE && rng && rng.setStart && doc.selection.createRange().item) {
         if (tinymce.isIE && ! tinymce.isIE11 && rng && rng.setStart && doc.selection.createRange().item) {
            elm = doc.selection.createRange().item(0);
            rng = doc.createRange();
            rng.setStartBefore(elm);
@@ -9928,6 +10407,16 @@
         return self;
      },
      scrollIntoView: function(elm) {
         var y, viewPort, self = this, dom = self.dom;
         viewPort = dom.getViewPort(self.editor.getWin());
         y = dom.getPos(elm).y;
         if (y < viewPort.y || y + 25 > viewPort.y + viewPort.h) {
            self.editor.getWin().scrollTo(0, y < viewPort.y ? y : y - viewPort.h + 25);
         }
      },
      destroy : function(manual) {
         var self = this;
@@ -10100,6 +10589,18 @@
         }
      });
      htmlParser.addNodeFilter('noscript', function(nodes) {
         var i = nodes.length, node;
         while (i--) {
            node = nodes[i].firstChild;
            if (node) {
               node.value = tinymce.html.Entities.decode(node.value);
            }
         }
      });
      // Force script into CDATA sections and remove the mce- prefix also add comments around styles
      htmlParser.addNodeFilter('script,style', function(nodes, name) {
         var i = nodes.length, node, value;
@@ -10257,7 +10758,7 @@
            // Replace all BOM characters for now until we can find a better solution
            if (!args.cleanup)
               args.content = args.content.replace(/\uFEFF|\u200B/g, '');
               args.content = args.content.replace(/\uFEFF/g, '');
            // Post process
            if (!args.no_events)
@@ -10358,7 +10859,7 @@
         // Add onload listener for non IE browsers since IE9
         // fires onload event before the script is parsed and executed
         if (!tinymce.isIE)
         if (!tinymce.isIE || tinymce.isIE11)
            elm.onload = done;
         // Add onerror event will get fired on some browsers but not all of them
@@ -10771,18 +11272,22 @@
            switch (evt.keyCode) {
               case DOM_VK_LEFT:
                  if (enableLeftRight) t.moveFocus(-1);
                  Event.cancel(evt);
                  break;
   
               case DOM_VK_RIGHT:
                  if (enableLeftRight) t.moveFocus(1);
                  Event.cancel(evt);
                  break;
   
               case DOM_VK_UP:
                  if (enableUpDown) t.moveFocus(-1);
                  Event.cancel(evt);
                  break;
               case DOM_VK_DOWN:
                  if (enableUpDown) t.moveFocus(1);
                  Event.cancel(evt);
                  break;
               case DOM_VK_ESCAPE:
@@ -11475,11 +11980,11 @@
         l = DOM.encode(s.label || '');
         h = '<a role="button" id="' + this.id + '" href="javascript:;" class="' + cp + ' ' + cp + 'Enabled ' + s['class'] + (l ? ' ' + cp + 'Labeled' : '') +'" onmousedown="return false;" onclick="return false;" aria-labelledby="' + this.id + '_voice" title="' + DOM.encode(s.title) + '">';
         if (s.image && !(this.editor  &&this.editor.forcedHighContrastMode) )
            h += '<img class="mceIcon" src="' + s.image + '" alt="' + DOM.encode(s.title) + '" />' + l;
            h += '<span class="mceIcon ' + s['class'] + '"><img class="mceIcon" src="' + s.image + '" alt="' + DOM.encode(s.title) + '" /></span>' + (l ? '<span class="' + cp + 'Label">' + l + '</span>' : '');
         else
            h += '<span class="mceIcon ' + s['class'] + '"></span>' + (l ? '<span class="' + cp + 'Label">' + l + '</span>' : '');
         h += '<span class="mceVoiceLabel mceIconOnly" style="display: none;" id="' + this.id + '_voice">' + s.title + '</span>';
         h += '<span class="mceVoiceLabel mceIconOnly" style="display: none;" id="' + this.id + '_voice">' + s.title + '</span>';
         h += '</a>';
         return h;
      },
@@ -11504,9 +12009,11 @@
               return s.onclick.call(s.scope, e);
            }
         });
         tinymce.dom.Event.add(t.id, 'keyup', function(e) {
            if (!t.isDisabled() && e.keyCode==tinymce.VK.SPACEBAR)
         tinymce.dom.Event.add(t.id, 'keydown', function(e) {
            if (!t.isDisabled() && e.keyCode==tinymce.VK.SPACEBAR) {
               tinymce.dom.Event.cancel(e);
               return s.onclick.call(s.scope, e);
            }
         });
      }
   });
@@ -11919,7 +12426,7 @@
         // Accessibility keyhandler
         Event.add(t.id, 'keydown', function(e) {
            var bf;
            var bf, DOM_VK_LEFT = 37, DOM_VK_RIGHT = 39, DOM_VK_UP = 38, DOM_VK_DOWN = 40, DOM_VK_RETURN = 13, DOM_VK_SPACE = 32;
            Event.remove(t.id, 'change', ch);
            changeListenerAdded = false;
@@ -11931,14 +12438,12 @@
               Event.remove(t.id, 'blur', bf);
            });
            //prevent default left and right keys on chrome - so that the keyboard navigation is used.
            if (tinymce.isWebKit && (e.keyCode==37 ||e.keyCode==39)) {
               return Event.prevent(e);
            }
            if (e.keyCode == 13 || e.keyCode == 32) {
            if (e.keyCode == DOM_VK_RETURN || e.keyCode == DOM_VK_SPACE) {
               onChange(e);
               return Event.cancel(e);
            } else if (e.keyCode == DOM_VK_DOWN || e.keyCode == DOM_VK_UP) {
               // allow native implementation (navigate select element options)
               e.stopImmediatePropagation();
            }
         });
@@ -12183,6 +12688,16 @@
            DOM.select('a', t.id + '_menu')[0].focus(); // Select first link
         }
         t.keyboardNav = new tinymce.ui.KeyboardNavigation({
            root: t.id + '_menu',
            items: DOM.select('a', t.id + '_menu'),
            onCancel: function() {
               t.hideMenu();
               t.focus();
            }
         });
         t.keyboardNav.focus();
         t.isMenuVisible = 1;
      },
@@ -12203,6 +12718,7 @@
            t.isMenuVisible = 0;
            t.onHideMenu.dispatch();
            t.keyboardNav.destroy();
         }
      },
@@ -12267,15 +12783,6 @@
         }
         DOM.addClass(m, 'mceColorSplitMenu');
         new tinymce.ui.KeyboardNavigation({
            root: t.id + '_menu',
            items: DOM.select('a', t.id + '_menu'),
            onCancel: function() {
               t.hideMenu();
               t.focus();
            }
         });
         // Prevent IE from scrolling and hindering click to occur #4019
         Event.add(t.id + '_menu', 'mousedown', function(e) {return Event.cancel(e);});
@@ -12317,11 +12824,17 @@
      },
      destroy : function() {
         this.parent();
         var self = this;
         Event.clear(this.id + '_menu');
         Event.clear(this.id + '_more');
         DOM.remove(this.id + '_menu');
         self.parent();
         Event.clear(self.id + '_menu');
         Event.clear(self.id + '_more');
         DOM.remove(self.id + '_menu');
         if (self.keyboardNav) {
            self.keyboardNav.destroy();
         }
      }
   });
})(tinymce);
@@ -12733,6 +13246,9 @@
         if (id === undef)
            return this.editors;
         if (!this.editors.hasOwnProperty(id))
            return undef;
         return this.editors[id];
      },
@@ -12816,7 +13332,7 @@
               ed.render();
               // Fix IE memory leaks
               if (tinymce.isIE) {
               if (tinymce.isIE && ! tinymce.isIE11) {
                  w.attachEvent('onunload', clr);
               }
@@ -12964,6 +13480,8 @@
         self.baseURI = tinymce.baseURI;
         self.contentCSS = [];
         self.contentStyles = [];
         // Creates all events like onClick, onSetContent etc see Editor.Events.js for the actual logic
         self.setupEvents();
@@ -13156,12 +13674,6 @@
         t.controlManager = new tinymce.ControlManager(t);
         t.onExecCommand.add(function(ed, c) {
            // Don't refresh the select lists until caret move
            if (!/^(FontName|FontSize)$/.test(c))
               t.nodeChanged();
         });
         // Enables users to override the control factory
         t.onBeforeRenderUI.dispatch(t, t.controlManager);
@@ -13218,9 +13730,15 @@
               // Store away the selection when it's changed to it can be restored later with a editor.focus() call
               if (isIE) {
                  t.onInit.add(function(ed) {
                     ed.dom.bind(ed.getBody(), 'beforedeactivate keydown', function() {
                        ed.lastIERng = ed.selection.getRng();
                     ed.dom.bind(ed.getBody(), 'beforedeactivate keydown keyup', function() {
                        ed.bookmark = ed.selection.getBookmark(1);
                     });
                  });
                  t.onNodeChange.add(function(ed) {
                     if (document.activeElement.id == ed.id + "_ifr") {
                        ed.bookmark = ed.selection.getBookmark(1);
                     }
                  });
               }
            }
@@ -13233,6 +13751,11 @@
            each(explode(s.content_css), function(u) {
               t.contentCSS.push(t.documentBaseURI.toAbsolute(u));
            });
         }
         // Load specified content CSS last
         if (s.content_style) {
            t.contentStyles.push(s.content_style);
         }
         // Content editable mode ends here
@@ -13253,10 +13776,12 @@
            t.iframeHTML += '<base href="' + t.documentBaseURI.getURI() + '" />';
         // IE8 doesn't support carets behind images setting ie7_compat would force IE8+ to run in IE7 compat mode.
         if (s.ie7_compat)
            t.iframeHTML += '<meta http-equiv="X-UA-Compatible" content="IE=7" />';
         else
            t.iframeHTML += '<meta http-equiv="X-UA-Compatible" content="IE=edge" />';
         if (tinymce.isIE8) {
            if (s.ie7_compat)
               t.iframeHTML += '<meta http-equiv="X-UA-Compatible" content="IE=7" />';
            else
               t.iframeHTML += '<meta http-equiv="X-UA-Compatible" content="IE=edge" />';
         }
         t.iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
@@ -13321,7 +13846,7 @@
      },
      initContentBody : function() {
         var self = this, settings = self.settings, targetElm = DOM.get(self.id), doc = self.getDoc(), html, body;
         var self = this, settings = self.settings, targetElm = DOM.get(self.id), doc = self.getDoc(), html, body, contentCssText;
         // Setup iframe body
         if ((!isIE || !tinymce.relaxedDomain) && !settings.content_editable) {
@@ -13430,6 +13955,12 @@
         self.enterKey = new tinymce.EnterKey(self);
         self.editorCommands = new tinymce.EditorCommands(self);
         self.onExecCommand.add(function(editor, command) {
            // Don't refresh the select lists until caret move
            if (!/^(FontName|FontSize)$/.test(command))
               self.nodeChanged();
         });
         // Pass through
         self.serializer.onPreProcess.add(function(se, o) {
            return self.onPreProcess.dispatch(self, o, se);
@@ -13492,6 +14023,17 @@
         self.focus(true);
         self.nodeChanged({initial : true});
         // Add editor specific CSS styles
         if (self.contentStyles.length > 0) {
            contentCssText = '';
            each(self.contentStyles, function(style) {
               contentCssText += style + "\r\n";
            });
            self.dom.addStyle(contentCssText);
         }
         // Load specified content CSS last
         each(self.contentCSS, function(url) {
            self.dom.loadCSS(url);
@@ -13517,8 +14059,9 @@
         var oed, self = this, selection = self.selection, contentEditable = self.settings.content_editable, ieRng, controlElm, doc = self.getDoc(), body;
         if (!skip_focus) {
            if (self.lastIERng) {
               selection.setRng(self.lastIERng);
            if (self.bookmark) {
               selection.moveToBookmark(self.bookmark);
               self.bookmark = null;
            }
            // Get selected control element
@@ -13539,7 +14082,7 @@
               body = self.getBody();
               // Check for setActive since it doesn't scroll to the element
               if (body.setActive) {
               if (body.setActive && ! tinymce.isIE11) {
                  body.setActive();
               } else {
                  body.focus();
@@ -13867,6 +14410,8 @@
         // We must save before we hide so Safari doesn't crash
         self.save();
         // defer the call to hide to prevent an IE9 crash #4921
         DOM.hide(self.getContainer());
         DOM.setStyle(self.id, 'display', self.orgDisplay);
      },
@@ -13992,7 +14537,7 @@
      },
      getContent : function(args) {
         var self = this, content;
         var self = this, content, body = self.getBody();
         // Setup args object
         args = args || {};
@@ -14006,11 +14551,18 @@
         // Get raw contents or by default the cleaned contents
         if (args.format == 'raw')
            content = self.getBody().innerHTML;
            content = body.innerHTML;
         else if (args.format == 'text')
            content = body.innerText || body.textContent;
         else
            content = self.serializer.serialize(self.getBody(), args);
            content = self.serializer.serialize(body, args);
         args.content = tinymce.trim(content);
         // Trim whitespace in beginning/end of HTML
         if (args.format != 'text') {
            args.content = tinymce.trim(content);
         } else {
            args.content = content;
         }
         // Do post processing
         if (!args.no_events)
@@ -14119,7 +14671,7 @@
                  return;
               case 'A':
                  if (!elm.href) {
                  if (!dom.getAttrib(elm, 'href', false)) {
                     value = dom.getAttrib(elm, 'name') || elm.id;
                     cls = 'mceItemAnchor';
@@ -14139,22 +14691,29 @@
      },
      remove : function() {
         var self = this, elm = self.getContainer();
         var self = this, elm = self.getContainer(), doc = self.getDoc();
         if (!self.removed) {
            self.removed = 1; // Cancels post remove event execution
            self.hide();
            // Fixed bug where IE has a blinking cursor left from the editor
            if (isIE && doc)
               doc.execCommand('SelectAll');
            // We must save before we hide so Safari doesn't crash
            self.save();
            DOM.setStyle(self.id, 'display', self.orgDisplay);
            // Don't clear the window or document if content editable
            // is enabled since other instances might still be present
            if (!self.settings.content_editable) {
               Event.clear(self.getWin());
               Event.clear(self.getDoc());
               Event.unbind(self.getWin());
               Event.unbind(self.getDoc());
            }
            Event.clear(self.getBody());
            Event.clear(self.formElement);
            Event.unbind(elm);
            Event.unbind(self.getBody());
            Event.clear(elm);
            self.execCallback('remove_instance_callback', self);
            self.onRemove.dispatch(self);
@@ -14356,8 +14915,10 @@
      // Handle legacy handle_event_callback option
      if (settings.handle_event_callback) {
         self.onEvent.add(function(ed, e, o) {
            if (self.execCallback('handle_event_callback', e, ed, o) === false)
               Event.cancel(e);
            if (self.execCallback('handle_event_callback', e, ed, o) === false) {
               e.preventDefault();
               e.stopPropagation();
            }
         });
      }
@@ -14423,9 +14984,12 @@
         self.focus(true);
      };
      function nodeChanged() {
         // Normalize selection for example <b>a</b><i>|a</i> becomes <b>a|</b><i>a</i>
         self.selection.normalize();
      function nodeChanged(ed, e) {
         // Normalize selection for example <b>a</b><i>|a</i> becomes <b>a|</b><i>a</i> except for Ctrl+A since it selects everything
         if (e.keyCode != 65 || !tinymce.VK.metaKeyPressed(e)) {
            self.selection.normalize();
         }
         self.nodeChanged();
      }
@@ -14469,7 +15033,7 @@
         var keyCode = e.keyCode;
         if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode == 13 || keyCode == 45 || keyCode == 46 || keyCode == 8 || (tinymce.isMac && (keyCode == 91 || keyCode == 93)) || e.ctrlKey)
            nodeChanged();
            nodeChanged(ed, e);
      });
      // Add reset handler
@@ -14822,7 +15386,7 @@
               // Insert bookmark node and get the parent
               selection.setContent(bookmarkHtml);
               parentNode = editor.selection.getNode();
               parentNode = selection.getNode();
               rootNode = editor.getBody();
               // Opera will return the document node when selection is in root
@@ -14894,6 +15458,10 @@
         mceInsertRawHTML : function(command, ui, value) {
            selection.setContent('tiny_mce_marker');
            editor.setContent(editor.getContent().replace(/tiny_mce_marker/g, function() { return value }));
         },
         mceToggleFormat : function(command, ui, value) {
            toggleFormat(value);
         },
         mceSetContent : function(command, ui, value) {
@@ -14985,10 +15553,15 @@
         selectAll : function() {
            var root = dom.getRoot(), rng = dom.createRng();
            rng.setStart(root, 0);
            rng.setEnd(root, root.childNodes.length);
            // Old IE does a better job with selectall than new versions
            if (selection.getRng().setStart) {
               rng.setStart(root, 0);
               rng.setEnd(root, root.childNodes.length);
            editor.selection.setRng(rng);
               selection.setRng(rng);
            } else {
               execNativeCommand('SelectAll');
            }
         }
      });
@@ -15027,7 +15600,10 @@
         },
         'InsertUnorderedList,InsertOrderedList' : function(command) {
            return dom.getParent(selection.getNode(), command == 'insertunorderedlist' ? 'UL' : 'OL');
            var list = dom.getParent(selection.getNode(), 'ul,ol');
            return list &&
                 (command === 'insertunorderedlist' && list.tagName === 'UL'
               || command === 'insertorderedlist' && list.tagName === 'OL');
         }
      }, 'state');
@@ -15120,7 +15696,7 @@
      // Add undo level on save contents, drag end and blur/focusout
      editor.onSaveContent.add(addNonTypingUndoLevel);
      editor.dom.bind(editor.dom.getRoot(), 'dragend', addNonTypingUndoLevel);
      editor.dom.bind(editor.getDoc(), tinymce.isGecko ? 'blur' : 'focusout', function(e) {
      editor.dom.bind(editor.getBody(), 'focusout', function(e) {
         if (!editor.removed && self.typing) {
            addNonTypingUndoLevel();
         }
@@ -15284,7 +15860,7 @@
   var settings = editor.settings, dom = editor.dom, selection = editor.selection, blockElements = editor.schema.getBlockElements();
   function addRootBlocks() {
      var node = selection.getStart(), rootNode = editor.getBody(), rng, startContainer, startOffset, endContainer, endOffset, rootBlockNode, tempNode, offset = -0xFFFFFF, wrapped;
      var node = selection.getStart(), rootNode = editor.getBody(), rng, startContainer, startOffset, endContainer, endOffset, rootBlockNode, tempNode, offset = -0xFFFFFF, wrapped, isInEditorDocument;
      if (!node || node.nodeType !== 1 || !settings.forced_root_block)
         return;
@@ -15312,6 +15888,7 @@
            rng.moveToElementText(node);
         }
         isInEditorDocument = rng.parentElement().ownerDocument === editor.getDoc();
         tmpRng = rng.duplicate();
         tmpRng.collapse(true);
         startOffset = tmpRng.move('character', offset) * -1;
@@ -15327,6 +15904,14 @@
      node = rootNode.firstChild;
      while (node) {
         if (node.nodeType === 3 || (node.nodeType == 1 && !blockElements[node.nodeName])) {
            // Remove empty text nodes
            if (node.nodeType === 3 && node.nodeValue.length == 0) {
               tempNode = node;
               node = node.nextSibling;
               dom.remove(tempNode);
               continue;
            }
            if (!rootBlockNode) {
               rootBlockNode = dom.create(settings.forced_root_block);
               node.parentNode.insertBefore(rootBlockNode, node);
@@ -15342,28 +15927,30 @@
         }
      }
      if (rng.setStart) {
         rng.setStart(startContainer, startOffset);
         rng.setEnd(endContainer, endOffset);
         selection.setRng(rng);
      } else {
         try {
            rng = editor.getDoc().body.createTextRange();
            rng.moveToElementText(rootNode);
            rng.collapse(true);
            rng.moveStart('character', startOffset);
            if (endOffset > 0)
               rng.moveEnd('character', endOffset);
            rng.select();
         } catch (ex) {
            // Ignore
         }
      }
      // Only trigger nodeChange when we wrapped nodes to prevent a forever loop
      if (wrapped) {
         if (rng.setStart) {
            rng.setStart(startContainer, startOffset);
            rng.setEnd(endContainer, endOffset);
            selection.setRng(rng);
         } else {
            // Only select if the previous selection was inside the document to prevent auto focus in quirks mode
            if (isInEditorDocument) {
               try {
                  rng = editor.getDoc().body.createTextRange();
                  rng.moveToElementText(rootNode);
                  rng.collapse(true);
                  rng.moveStart('character', startOffset);
                  if (endOffset > 0)
                     rng.moveEnd('character', endOffset);
                  rng.select();
               } catch (ex) {
                  // Ignore
               }
            }
         }
         editor.nodeChanged();
      }
   };
@@ -15892,10 +16479,11 @@
         TreeWalker = tinymce.dom.TreeWalker,
         rangeUtils = new tinymce.dom.RangeUtils(dom),
         isValid = ed.schema.isValidChild,
         isArray = tinymce.isArray,
         isBlock = dom.isBlock,
         forcedRootBlock = ed.settings.forced_root_block,
         nodeIndex = dom.nodeIndex,
         INVISIBLE_CHAR = tinymce.isGecko ? '\u200B' : '\uFEFF',
         INVISIBLE_CHAR = '\uFEFF',
         MCE_ATTR_RE = /^(src|href|style)$/,
         FALSE = false,
         TRUE = true,
@@ -15903,9 +16491,13 @@
         undef,
         getContentEditable = dom.getContentEditable;
      function isArray(obj) {
         return obj instanceof Array;
      };
      function isTextBlock(name) {
         if (name.nodeType) {
            name = name.nodeName;
         }
         return !!ed.schema.getTextBlockElements()[name.toLowerCase()];
      }
      function getParents(node, selector) {
         return dom.getParents(node, selector, dom.getRoot());
@@ -16265,7 +16857,7 @@
                  // Is it valid to wrap this item
                  if (contentEditable && !hasContentEditableState && isValid(wrapName, nodeName) && isValid(parentName, wrapName) &&
                        !(!node_specific && node.nodeType === 3 && node.nodeValue.length === 1 && node.nodeValue.charCodeAt(0) === 65279) && !isCaretNode(node)) {
                        !(!node_specific && node.nodeType === 3 && node.nodeValue.length === 1 && node.nodeValue.charCodeAt(0) === 65279) && !isCaretNode(node) && (!format.inline || !isBlock(node))) {
                     // Start wrapping
                     if (!currentWrapElm) {
                        // Wrap the node
@@ -16470,6 +17062,11 @@
         // Merges the styles for each node
         function process(node) {
            var children, i, l, localContentEditable, lastContentEditable, hasContentEditableState;
            // Skip on text nodes as they have neither format to remove nor children
            if (node.nodeType === 3) {
               return;
            }
            // Node has a contentEditable value
            if (node.nodeType === 1 && getContentEditable(node)) {
@@ -16810,7 +17407,7 @@
         return FALSE;
      };
      function formatChanged(formats, callback) {
      function formatChanged(formats, callback, similar) {
         var currentFormats;
         // Setup format node change logic
@@ -16824,7 +17421,7 @@
               // Check for new formats
               each(formatChangeData, function(callbacks, format) {
                  each(parents, function(node) {
                     if (matchNode(node, format, {}, true)) {
                     if (matchNode(node, format, {}, callbacks.similar)) {
                        if (!currentFormats[format]) {
                           // Execute callbacks
                           each(callbacks, function(callback) {
@@ -16857,6 +17454,7 @@
         each(formats.split(','), function(format) {
            if (!formatChangeData[format]) {
               formatChangeData[format] = [];
               formatChangeData[format].similar = similar;
            }
            formatChangeData[format].push(callback);
@@ -16963,6 +17561,10 @@
            siblingName = start ? 'previousSibling' : 'nextSibling';
            root = dom.getRoot();
            function isBogusBr(node) {
               return node.nodeName == "BR" && node.getAttribute('data-mce-bogus') && !node.nextSibling;
            };
            // If it's a text node and the offset is inside the text
            if (container.nodeType == 3 && !isWhiteSpaceNode(container)) {
               if (start ? startOffset > 0 : endOffset < container.nodeValue.length) {
@@ -16977,7 +17579,7 @@
               // Walk left/right
               for (sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
                  if (!isBookmarkNode(sibling) && !isWhiteSpaceNode(sibling)) {
                  if (!isBookmarkNode(sibling) && !isWhiteSpaceNode(sibling) && !isBogusBr(sibling)) {
                     return parent;
                  }
               }
@@ -17136,7 +17738,7 @@
            // Expand to first wrappable block element or any block element
            if (!node)
               node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, isBlock);
               node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, isTextBlock);
            // Exclude inner lists from wrapping
            if (node && format[0].wrapper)
@@ -17535,10 +18137,6 @@
         return next;
      };
      function isTextBlock(name) {
         return /^(h[1-6]|p|div|pre|address|dl|dt|dd)$/.test(name);
      };
      function getContainer(rng, start) {
         var container, offset, lastIdx, walker;
@@ -17774,11 +18372,23 @@
               node.appendChild(dom.doc.createTextNode(INVISIBLE_CHAR));
               node = node.firstChild;
               // Insert caret container after the formated node
               dom.insertAfter(caretContainer, formatNode);
               var block = dom.getParent(formatNode, isTextBlock);
               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 {
                  // Insert caret container after the formated node
                  dom.insertAfter(caretContainer, formatNode);
               }
               // Move selection to text node
               selection.setCursorLocation(node, 1);
               // If the formatNode is empty, we can remove it safely.
               if (dom.isEmpty(formatNode)) {
                  dom.remove(formatNode);
               }
            }
         };
@@ -17949,21 +18559,63 @@
   var TreeWalker = tinymce.dom.TreeWalker;
   tinymce.EnterKey = function(editor) {
      var dom = editor.dom, selection = editor.selection, settings = editor.settings, undoManager = editor.undoManager;
      var dom = editor.dom, selection = editor.selection, settings = editor.settings, undoManager = editor.undoManager, nonEmptyElementsMap = editor.schema.getNonEmptyElements();
      function handleEnterKey(evt) {
         var rng = selection.getRng(true), tmpRng, editableRoot, container, offset, parentBlock, documentMode,
         var rng = selection.getRng(true), tmpRng, editableRoot, container, offset, parentBlock, documentMode, shiftKey,
            newBlock, fragment, containerBlock, parentBlockName, containerBlockName, newBlockName, isAfterLastNodeInContainer;
         // Returns true if the block can be split into two blocks or not
         function canSplitBlock(node) {
            return node &&
               dom.isBlock(node) &&
               !/^(TD|TH|CAPTION)$/.test(node.nodeName) &&
               !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) &&
               !/^(fixed|absolute)/i.test(node.style.position) && 
               dom.getContentEditable(node) !== "true";
         };
         // Renders empty block on IE
         function renderBlockOnIE(block) {
            var oldRng;
            if (tinymce.isIE && !tinymce.isIE11 && dom.isBlock(block)) {
               oldRng = selection.getRng();
               block.appendChild(dom.create('span', null, '\u00a0'));
               selection.select(block);
               block.lastChild.outerHTML = '';
               selection.setRng(oldRng);
            }
         };
         // Remove the first empty inline element of the block so this: <p><b><em></em></b>x</p> becomes this: <p>x</p>
         function trimInlineElementsOnLeftSideOfBlock(block) {
            var node = block, firstChilds = [], i;
            // Find inner most first child ex: <p><i><b>*</b></i></p>
            while (node = node.firstChild) {
               if (dom.isBlock(node)) {
                  return;
               }
               if (node.nodeType == 1 && !nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
                  firstChilds.push(node);
               }
            }
            i = firstChilds.length;
            while (i--) {
               node = firstChilds[i];
               if (!node.hasChildNodes() || (node.firstChild == node.lastChild && node.firstChild.nodeValue === '')) {
                  dom.remove(node);
               } else {
                  // Remove <a> </a> see #5381
                  if (node.nodeName == "A" && (node.innerText || node.textContent) === ' ') {
                     dom.remove(node);
                  }
               }
            }
         };
         // Moves the caret to a suitable position within the root for example in the first non pure whitespace text node or before an image
         function moveToCaretPosition(root) {
            var walker, node, rng, y, viewPort, lastNode = root, tempElm;
@@ -17980,7 +18632,7 @@
                     break;
                  }
                  if (/^(BR|IMG)$/.test(node.nodeName)) {
                  if (nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
                     rng.setStartBefore(node);
                     rng.setEndBefore(node);
                     break;
@@ -18041,6 +18693,11 @@
            if (settings.keep_styles !== false) {
               do {
                  if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(node.nodeName)) {
                     // Never clone a caret containers
                     if (node.id == '_mce_caret') {
                        continue;
                     }
                     clonedNode = node.cloneNode(false);
                     dom.setAttrib(clonedNode, 'id', ''); // Remove ID since it needs to be document unique
@@ -18056,8 +18713,8 @@
            }
            // BR is needed in empty blocks on non IE browsers
            if (!tinymce.isIE) {
               caretNode.innerHTML = '<br>';
            if (!tinymce.isIE || tinymce.isIE11) {
               caretNode.innerHTML = '<br data-mce-bogus="1">';
            }
            return block;
@@ -18077,6 +18734,11 @@
               return true;
            }
            // If the caret if before the first element in parentBlock
            if (start && container.nodeType == 1 && container == parentBlock.firstChild) {
               return true;
            }
            // Caret can be before/after a table
            if (container.nodeName === "TABLE" || (container.previousSibling && container.previousSibling.nodeName == "TABLE")) {
               return (isAfterLastNodeInContainer && !start) || (!isAfterLastNodeInContainer && start);
@@ -18084,20 +18746,34 @@
            // Walk the DOM and look for text nodes or non empty elements
            walker = new TreeWalker(container, parentBlock);
            while (node = (start ? walker.prev() : walker.next())) {
            // If caret is in beginning or end of a text block then jump to the next/previous node
            if (container.nodeType == 3) {
               if (start && offset == 0) {
                  walker.prev();
               } else if (!start && offset == container.nodeValue.length) {
                  walker.next();
               }
            }
            while (node = walker.current()) {
               if (node.nodeType === 1) {
                  // Ignore bogus elements
                  if (node.getAttribute('data-mce-bogus')) {
                     continue;
                  }
                  // Keep empty elements like <img />
                  name = node.nodeName.toLowerCase();
                  if (name === 'IMG') {
                     return false;
                  if (!node.getAttribute('data-mce-bogus')) {
                     // Keep empty elements like <img /> <input /> but not trailing br:s like <p>text|<br></p>
                     name = node.nodeName.toLowerCase();
                     if (nonEmptyElementsMap[name] && name !== 'br') {
                        return false;
                     }
                  }
               } else if (node.nodeType === 3 && !/^[ \t\r\n]*$/.test(node.nodeValue)) {
                  return false;
               }
               if (start) {
                  walker.prev();
               } else {
                  walker.next();
               }
            }
@@ -18182,6 +18858,7 @@
            } else if (isFirstOrLastLi()) {
               // Last LI in list then temove LI and add text block after list
               dom.insertAfter(newBlock, containerBlock);
               renderBlockOnIE(newBlock);
            } else {
               // Middle LI in list the split the list and insert a text block in the middle
               // Extract after fragment and insert it after the current block
@@ -18198,27 +18875,25 @@
            undoManager.add();
         };
         // Walks the parent block to the right and look for BR elements
         function hasRightSideBr() {
         // Walks the parent block to the right and look for any contents
         function hasRightSideContent() {
            var walker = new TreeWalker(container, parentBlock), node;
            while (node = walker.current()) {
               if (node.nodeName == 'BR') {
            while (node = walker.next()) {
               if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || node.length > 0) {
                  return true;
               }
               node = walker.next();
            }
         }
         // Inserts a BR element if the forced_root_block option is set to false or empty string
         function insertBr() {
            var brElm, extraBr;
            var brElm, extraBr, marker;
            if (container && container.nodeType == 3 && offset >= container.nodeValue.length) {
               // Insert extra BR element at the end block elements
               if (!tinymce.isIE && !hasRightSideBr()) {
                  brElm = dom.create('br')
               if ((!tinymce.isIE || tinymce.isIE11) && !hasRightSideContent()) {
                  brElm = dom.create('br');
                  rng.insertNode(brElm);
                  rng.setStartAfter(brElm);
                  rng.setEndAfter(brElm);
@@ -18230,9 +18905,15 @@
            rng.insertNode(brElm);
            // Rendering modes below IE8 doesn't display BR elements in PRE unless we have a \n before it
            if (tinymce.isIE && parentBlockName == 'PRE' && (!documentMode || documentMode < 8)) {
            if ((tinymce.isIE && !tinymce.isIE11) && parentBlockName == 'PRE' && (!documentMode || documentMode < 8)) {
               brElm.parentNode.insertBefore(dom.doc.createTextNode('\r'), brElm);
            }
            // Insert temp marker and scroll to that
            marker = dom.create('span', {}, '&nbsp;');
            brElm.parentNode.insertBefore(marker, brElm);
            selection.scrollIntoView(marker);
            dom.remove(marker);
            if (!extraBr) {
               rng.setStartAfter(brElm);
@@ -18273,6 +18954,22 @@
            return parent !== root ? editableRoot : root;
         };
         // Adds a BR at the end of blocks that only contains an IMG or INPUT since these might be floated and then they won't expand the block
         function addBrToBlockIfNeeded(block) {
            var lastChild;
            // IE will render the blocks correctly other browsers needs a BR
            if (!tinymce.isIE || tinymce.isIE11) {
               block.normalize(); // Remove empty text nodes that got left behind by the extract
               // Check if the block is empty or contains a floated last child
               lastChild = block.lastChild;
               if (!lastChild || (/^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true)))) {
                  dom.add(block, 'br');
               }
            }
         };
         // Delete any selected contents
         if (!rng.collapsed) {
            editor.execCommand('Delete');
@@ -18287,15 +18984,20 @@
         // Setup range items and newBlockName
         container = rng.startContainer;
         offset = rng.startOffset;
         newBlockName = settings.forced_root_block;
         newBlockName = (settings.force_p_newlines ? 'p' : '') || settings.forced_root_block;
         newBlockName = newBlockName ? newBlockName.toUpperCase() : '';
         documentMode = dom.doc.documentMode;
         shiftKey = evt.shiftKey;
         // Resolve node index
         if (container.nodeType == 1 && container.hasChildNodes()) {
            isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
            container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
            offset = 0;
            if (isAfterLastNodeInContainer && container.nodeType == 3) {
               offset = container.nodeValue.length;
            } else {
               offset = 0;
            }
         }
         // Get editable root node normaly the body element but sometimes a div or span
@@ -18310,7 +19012,7 @@
         // If editable root isn't block nor the root of the editor
         if (!dom.isBlock(editableRoot) && editableRoot != dom.getRoot()) {
            if (!newBlockName || evt.shiftKey) {
            if (!newBlockName || shiftKey) {
               insertBr();
            }
@@ -18320,7 +19022,7 @@
         // Wrap the current node and it's sibling in a default block if it's needed.
         // for example this <td>text|<b>text2</b></td> will become this <td><p>text|<b>text2</p></b></td>
         // This won't happen if root blocks are disabled or the shiftKey is pressed
         if ((newBlockName && !evt.shiftKey) || (!newBlockName && evt.shiftKey)) {
         if ((newBlockName && !shiftKey) || (!newBlockName && shiftKey)) {
            container = wrapSelfAndSiblingsInDefaultBlock(container, offset);
         }
@@ -18332,26 +19034,40 @@
         parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
         containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
         // Handle enter inside an empty list item
         if (parentBlockName == 'LI' && dom.isEmpty(parentBlock)) {
            // Let the list plugin or browser handle nested lists for now
            if (/^(UL|OL|LI)$/.test(containerBlock.parentNode.nodeName)) {
               return false;
         // Enter inside block contained within a LI then split or insert before/after LI
         if (containerBlockName == 'LI' && !evt.ctrlKey) {
            parentBlock = containerBlock;
            parentBlockName = containerBlockName;
         }
         // Handle enter in LI
         if (parentBlockName == 'LI') {
            if (!newBlockName && shiftKey) {
               insertBr();
               return;
            }
            handleEmptyListItem();
            return;
            // Handle enter inside an empty list item
            if (dom.isEmpty(parentBlock)) {
               // Let the list plugin or browser handle nested lists for now
               if (/^(UL|OL|LI)$/.test(containerBlock.parentNode.nodeName)) {
                  return false;
               }
               handleEmptyListItem();
               return;
            }
         }
         // Don't split PRE tags but insert a BR instead easier when writing code samples etc
         if (parentBlockName == 'PRE' && settings.br_in_pre !== false) {
            if (!evt.shiftKey) {
            if (!shiftKey) {
               insertBr();
               return;
            }
         } else {
            // If no root block is configured then insert a BR by default or if the shiftKey is pressed
            if ((!newBlockName && !evt.shiftKey && parentBlockName != 'LI') || (newBlockName && evt.shiftKey)) {
            if ((!newBlockName && !shiftKey && parentBlockName != 'LI') || (newBlockName && shiftKey)) {
               insertBr();
               return;
            }
@@ -18376,9 +19092,12 @@
            } else {
               dom.insertAfter(newBlock, parentBlock);
            }
            moveToCaretPosition(newBlock);
         } else if (isCaretAtStartOrEndOfBlock(true)) {
            // Insert new block before
            newBlock = parentBlock.parentNode.insertBefore(createNewBlock(), parentBlock);
            renderBlockOnIE(newBlock);
         } else {
            // Extract after fragment and insert it after the current block
            tmpRng = rng.cloneRange();
@@ -18387,10 +19106,12 @@
            trimLeadingLineBreaks(fragment);
            newBlock = fragment.firstChild;
            dom.insertAfter(fragment, parentBlock);
            trimInlineElementsOnLeftSideOfBlock(newBlock);
            addBrToBlockIfNeeded(parentBlock);
            moveToCaretPosition(newBlock);
         }
         dom.setAttrib(newBlock, 'id', ''); // Remove ID since it needs to be document unique
         moveToCaretPosition(newBlock);
         undoManager.add();
      }