+ * Traverse with {@link CKEDITOR.dom.walker} to retrieve the previous element before the range start.\r
+ * @param {Function} evaluator Function used as the walker's evaluator.\r
+ * @param {Function} [guard] Function used as the walker's guard.\r
+ * @param {CKEDITOR.dom.element} [boundary] A range ancestor element in which the traversal is limited,\r
+ * default to the root editable if not defined.\r
+ *\r
+ * @return {CKEDITOR.dom.element|null} The returned node from the traversal.\r
+ */\r
+ getPreviousNode : function( evaluator, guard, boundary ) {\r
+\r
+ var walkerRange = this.clone();\r
+ walkerRange.collapse( 1 );\r
+ walkerRange.setStartAt( boundary || this.document.getBody(), CKEDITOR.POSITION_AFTER_START );\r
+\r
+ var walker = new CKEDITOR.dom.walker( walkerRange );\r
+ walker.evaluator = evaluator;\r
+ walker.guard = guard;\r
+ return walker.previous();\r
+ },\r
+\r
+ /**\r
+ * Traverse with {@link CKEDITOR.dom.walker} to retrieve the next element before the range start.\r
+ * @param {Function} evaluator Function used as the walker's evaluator.\r
+ * @param {Function} [guard] Function used as the walker's guard.\r
+ * @param {CKEDITOR.dom.element} [boundary] A range ancestor element in which the traversal is limited,\r
+ * default to the root editable if not defined.\r
+ *\r
+ * @return {CKEDITOR.dom.element|null} The returned node from the traversal.\r
+ */\r
+ getNextNode: function( evaluator, guard, boundary )\r
+ {\r
+ var walkerRange = this.clone();\r
+ walkerRange.collapse();\r
+ walkerRange.setEndAt( boundary || this.document.getBody(), CKEDITOR.POSITION_BEFORE_END );\r
+\r
+ var walker = new CKEDITOR.dom.walker( walkerRange );\r
+ walker.evaluator = evaluator;\r
+ walker.guard = guard;\r
+ return walker.next();\r
+ },\r
+\r
+ checkReadOnly : ( function()\r
+ {\r
+ function checkNodesEditable( node, anotherEnd )\r
+ {\r
+ while( node )\r
+ {\r
+ if ( node.type == CKEDITOR.NODE_ELEMENT )\r
+ {\r
+ if ( node.getAttribute( 'contentEditable' ) == 'false'\r
+ && !node.data( 'cke-editable' ) )\r
+ {\r
+ return 0;\r
+ }\r
+ // Range enclosed entirely in an editable element.\r
+ else if ( node.is( 'html' )\r
+ || node.getAttribute( 'contentEditable' ) == 'true'\r
+ && ( node.contains( anotherEnd ) || node.equals( anotherEnd ) ) )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ node = node.getParent();\r
+ }\r
+\r
+ return 1;\r
+ }\r
+\r
+ return function()\r
+ {\r
+ var startNode = this.startContainer,\r
+ endNode = this.endContainer;\r
+\r
+ // Check if elements path at both boundaries are editable.\r
+ return !( checkNodesEditable( startNode, endNode ) && checkNodesEditable( endNode, startNode ) );\r
+ };\r
+ })(),\r
+\r
+ /**\r