/**
 * ForceBlocks.js
 *
 * Copyright, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

tinymce.ForceBlocks = function(editor) {
	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, isInEditorDocument;

		if (!node || node.nodeType !== 1 || !settings.forced_root_block)
			return;

		// Check if node is wrapped in block
		while (node && node != rootNode) {
			if (blockElements[node.nodeName])
				return;

			node = node.parentNode;
		}

		// Get current selection
		rng = selection.getRng();
		if (rng.setStart) {
			startContainer = rng.startContainer;
			startOffset = rng.startOffset;
			endContainer = rng.endContainer;
			endOffset = rng.endOffset;
		} else {
			// Force control range into text range
			if (rng.item) {
				node = rng.item(0);
				rng = editor.getDoc().body.createTextRange();
				rng.moveToElementText(node);
			}

			isInEditorDocument = rng.parentElement().ownerDocument === editor.getDoc();
			tmpRng = rng.duplicate();
			tmpRng.collapse(true);
			startOffset = tmpRng.move('character', offset) * -1;

			if (!tmpRng.collapsed) {
				tmpRng = rng.duplicate();
				tmpRng.collapse(false);
				endOffset = (tmpRng.move('character', offset) * -1) - startOffset;
			}
		}

		// Wrap non block elements and text nodes
		node = rootNode.firstChild;
		while (node) {
			if (node.nodeType === 3 || (node.nodeType == 1 && !blockElements[node.nodeName] && !node.getAttribute('data-mce-type'))) {
				// 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);
					wrapped = true;
				}

				tempNode = node;
				node = node.nextSibling;
				rootBlockNode.appendChild(tempNode);
			} else {
				rootBlockNode = null;
				node = node.nextSibling;
			}
		}

		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();
		}
	};

	// Force root blocks
	if (settings.forced_root_block) {
		editor.onKeyUp.add(addRootBlocks);
		editor.onNodeChange.add(addRootBlocks);
	}
};

@@ -1076,16 +1076,180 @@
 ffset;%0D%0A
+%09%09%09%0D%0A%09%09%09try %7B%0D%0A%09%09%09%09restoreSelection = editor.getDoc().activeElement === rootNode;%0D%0A%09%09%09%7D catch (ex) %7B%0D%0A%09%09%09%09// IE throws unspecified error here sometimes%0D%0A%09%09%09%7D%0D%0A%09%09%09%0D%0A
 %09%09%7D else
@@ -1436,34 +1436,32 @@
 %7D%0D%0A%0D%0A%09%09%09
-isInEditorDocument
+restoreSelection
  = rng.p
@@ -2590,21 +2590,42 @@
 (wrapped
+ && restoreSelection
 ) %7B%0D%0A
+%09
 %09%09%09if (r
@@ -2636,24 +2636,25 @@
 etStart) %7B%0D%0A
+%09
 %09%09%09%09rng.setS
@@ -2689,24 +2689,25 @@
 fset);%0D%0A%09%09%09%09
+%09
 rng.setEnd(e
@@ -2736,16 +2736,17 @@
 );%0D%0A%09%09%09%09
+%09
 selectio
@@ -2760,24 +2760,25 @@
 g(rng);%0D%0A%09%09%09
+%09
 %7D else %7B%0D%0A%09%09
@@ -2771,24 +2771,25 @@
 %09%09%7D else %7B%0D%0A
+%09
 %09%09%09%09// Only 
@@ -2887,39 +2887,8 @@
 de%0D%0A
-%09%09%09%09if (isInEditorDocument) %7B%0D%0A
 %09%09%09%09
@@ -3089,16 +3089,18 @@
 set %3E 0)
+ %7B
 %0D%0A%09%09%09%09%09%09
@@ -3129,32 +3129,41 @@
 r', endOffset);%0D
+%0A%09%09%09%09%09%09%7D%0D
 %0A%0D%0A%09%09%09%09%09%09rng.sel
@@ -3223,24 +3223,19 @@
 %0A%09%09%09%09%7D%0D%0A
-%09%09%09%7D%0D%0A
 %0D%0A
+%09
 %09%09%09edito
@@ -3252,16 +3252,17 @@
 ged();%0D%0A
+%09
 %09%09%7D%0D%0A%09%7D;

Update with TinyMCE 4 fixes / changes