JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.4b
[ckeditor.git] / _source / core / dom / rangelist.js
diff --git a/_source/core/dom/rangelist.js b/_source/core/dom/rangelist.js
new file mode 100644 (file)
index 0000000..9c12e48
--- /dev/null
@@ -0,0 +1,163 @@
+/*\r
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
+For licensing, see LICENSE.html or http://ckeditor.com/license\r
+*/\r
+\r
+(function()\r
+{\r
+       /**\r
+        * Represents a list os CKEDITOR.dom.range objects, which can be easily\r
+        * iterated sequentially.\r
+        * @constructor\r
+        * @param {CKEDITOR.dom.range|Array} [ranges] The ranges contained on this list.\r
+        *              Note that, if an array of ranges is specified, the range sequence\r
+        *              should match its DOM order. This class will not help to sort them.\r
+        */\r
+       CKEDITOR.dom.rangeList = function( ranges )\r
+       {\r
+               if ( ranges instanceof CKEDITOR.dom.rangeList )\r
+                       return ranges;\r
+\r
+               if ( !ranges )\r
+                       ranges = [];\r
+               else if ( ranges instanceof CKEDITOR.dom.range )\r
+                       ranges = [ ranges ];\r
+\r
+               return CKEDITOR.tools.extend( ranges, mixins );\r
+       };\r
+\r
+       var mixins =\r
+       /** @lends CKEDITOR.dom.rangeList.prototype */\r
+       {\r
+                       /**\r
+                        * Creates an instance of the rangeList iterator, it should be used\r
+                        * only when the ranges processing could be DOM intrusive, which\r
+                        * means it may pollute and break other ranges in this list.\r
+                        * Otherwise, it's enough to just iterate over this array in a for loop.\r
+                        * @returns {CKEDITOR.dom.rangeListIterator}\r
+                        */\r
+                       createIterator : function()\r
+                       {\r
+                               var rangeList = this,\r
+                                       bookmarks = [],\r
+                                       current;\r
+\r
+                               /**\r
+                                * @lends CKEDITOR.dom.rangeListIterator.prototype\r
+                                */\r
+                               return {\r
+\r
+                                       /**\r
+                                        * Retrieves the next range in the list.\r
+                                        */\r
+                                       getNextRange : function()\r
+                                       {\r
+                                               current = current == undefined ? 0 : current + 1;\r
+\r
+                                               var range = rangeList[ current ];\r
+\r
+                                               // Multiple ranges might be mangled by each other.\r
+                                               if ( range && rangeList.length > 1 )\r
+                                               {\r
+                                                       // Bookmarking all other ranges on the first iteration,\r
+                                                       // the range correctness after it doesn't matter since we'll\r
+                                                       // restore them before the next iteration.\r
+                                                       if ( !current )\r
+                                                       {\r
+                                                               // Make sure bookmark correctness by reverse processing.\r
+                                                               for ( var i = rangeList.length - 1; i > 0; i-- )\r
+                                                                       bookmarks.unshift( rangeList[ i ].createBookmark( true ) );\r
+                                                       }\r
+                                                       else\r
+                                                               range.moveToBookmark( bookmarks.shift() );\r
+                                               }\r
+\r
+                                               return range;\r
+                                       }\r
+                               };\r
+                       },\r
+\r
+                       createBookmarks : function( serializable )\r
+                       {\r
+                               var retval = [], bookmark;\r
+                               for ( var i = 0; i < this.length ; i++ )\r
+                               {\r
+                                       retval.push( bookmark = this[ i ].createBookmark( serializable, true) );\r
+\r
+                                       // Updating the container & offset values for ranges\r
+                                       // that have been touched.\r
+                                       for ( var j = i + 1; j < this.length; j++ )\r
+                                       {\r
+                                               this[ j ] = updateDirtyRange( bookmark, this[ j ] );\r
+                                               this[ j ] = updateDirtyRange( bookmark, this[ j ], true );\r
+                                       }\r
+                               }\r
+                               return retval;\r
+                       },\r
+\r
+                       createBookmarks2 : function( normalized )\r
+                       {\r
+                               var bookmarks = [];\r
+\r
+                               for ( var i = 0 ; i < this.length ; i++ )\r
+                                       bookmarks.push( this[ i ].createBookmark2( normalized ) );\r
+\r
+                               return bookmarks;\r
+                       },\r
+\r
+                       /**\r
+                        * Move each range in the list to the position specified by a list of bookmarks.\r
+                        * @param {Array} bookmarks The list of bookmarks, each one matching a range in the list.\r
+                        */\r
+                       moveToBookmarks :  function( bookmarks )\r
+                       {\r
+                               for ( var i = 0 ; i < this.length ; i++ )\r
+                                       this[ i ].moveToBookmark( bookmarks[ i ] );\r
+                       }\r
+       };\r
+\r
+       // Update the specified range which has been mangled by previous insertion of\r
+       // range bookmark nodes.(#3256)\r
+       function updateDirtyRange( bookmark, dirtyRange, checkEnd )\r
+       {\r
+               var serializable = bookmark.serializable,\r
+                       container = dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ],\r
+                       offset = checkEnd ? 'endOffset' : 'startOffset';\r
+\r
+               var bookmarkStart = serializable ?\r
+                               dirtyRange.document.getById( bookmark.startNode )\r
+                               : bookmark.startNode;\r
+\r
+               var bookmarkEnd = serializable ?\r
+                               dirtyRange.document.getById( bookmark.endNode )\r
+                               : bookmark.endNode;\r
+\r
+               if ( container.equals( bookmarkStart.getPrevious() ) )\r
+               {\r
+                       dirtyRange.startOffset = dirtyRange.startOffset\r
+                                       - container.getLength()\r
+                                       - bookmarkEnd.getPrevious().getLength();\r
+                       container = bookmarkEnd.getNext();\r
+               }\r
+               else if ( container.equals( bookmarkEnd.getPrevious() ) )\r
+               {\r
+                       dirtyRange.startOffset = dirtyRange.startOffset - container.getLength();\r
+                       container = bookmarkEnd.getNext();\r
+               }\r
+\r
+               container.equals( bookmarkStart.getParent() ) && dirtyRange[ offset ]++;\r
+               container.equals( bookmarkEnd.getParent() ) && dirtyRange[ offset ]++;\r
+\r
+               // Update and return this range.\r
+               dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ] = container;\r
+               return dirtyRange;\r
+       }\r
+})();\r
+\r
+/**\r
+ * (Virtual Class) Do not call this constructor. This class is not really part\r
+ *     of the API. It just describes the return type of {@link CKEDITOR.dom.rangeList#createIterator}.\r
+ * @name CKEDITOR.dom.rangeListIterator\r
+ * @constructor\r
+ * @example\r
+ */\r