Index: trunk/extensions/VisualEditor/modules/es/models/es.DocumentModel.js |
— | — | @@ -832,12 +832,13 @@ |
833 | 833 | */ |
834 | 834 | function strip( tx, node, range, offset ) { |
835 | 835 | var childNodes = node.getChildren(), |
836 | | - selectedNodes = node.selectNodes( range ), |
| 836 | + selectedNodes = node.selectNodes( range, true ), |
837 | 837 | rules = es.DocumentModel.nodeRules, |
838 | 838 | left = offset || 0, |
839 | 839 | right, |
840 | 840 | elementLength, |
841 | 841 | selectedNode; |
| 842 | + offset = offset || 0; |
842 | 843 | for ( var i = 0; i < childNodes.length; i++ ) { |
843 | 844 | if ( selectedNodes.length && childNodes[i] === selectedNodes[0].node ) { |
844 | 845 | for ( var j = 0; j < selectedNodes.length; j++ ) { |
— | — | @@ -867,8 +868,8 @@ |
868 | 869 | if ( selectedNode.globalRange.getLength() ) { |
869 | 870 | tx.pushRemove( |
870 | 871 | doc.data.slice( |
871 | | - selectedNode.globalRange.start, |
872 | | - selectedNode.globalRange.end |
| 872 | + selectedNode.globalRange.start + offset, |
| 873 | + selectedNode.globalRange.end + offset |
873 | 874 | ) |
874 | 875 | ); |
875 | 876 | } |
— | — | @@ -901,21 +902,9 @@ |
902 | 903 | // So you can merge adjacent paragraphs, or listitems. And you can't merge a paragraph into |
903 | 904 | // a table row. There may be other rules we will want in here later, for instance, special |
904 | 905 | // casing merging a listitem into a paragraph. |
905 | | - if ( |
906 | | - // [<p>a</p><p>b</p>] |
907 | | - ( |
908 | | - node1 && |
909 | | - node2 && |
910 | | - node1.getElementType() === node2.getElementType() && |
911 | | - node1.getParent() === node2.getParent() |
912 | | - ) || |
913 | | - // [<p>a</p>]<p>b</p> |
914 | | - ( |
915 | | - node1 && |
916 | | - node2 && |
917 | | - node1 === node2 && |
918 | | - range.start < range.end |
919 | | - ) |
| 906 | + if ( node1 && node2 && |
| 907 | + node1.getElementType() === node2.getElementType() && |
| 908 | + node1.getParent() === node2.getParent() |
920 | 909 | ) { |
921 | 910 | // Retain to the start of the range |
922 | 911 | if ( range.start > 0 ) { |
— | — | @@ -936,6 +925,101 @@ |
937 | 926 | }; |
938 | 927 | |
939 | 928 | /** |
| 929 | + * Generates a transaction which removes data from a given range. |
| 930 | + * |
| 931 | + * When removing data inside an element, the data is simply discarded and the node's length is |
| 932 | + * adjusted accordingly. When removing data across elements, there are two situations that can cause |
| 933 | + * added complexity: |
| 934 | + * 1. A range spans between nodes of different levels or types |
| 935 | + * 2. A range only partially covers one or two nodes |
| 936 | + * |
| 937 | + * To resolve these issues in a predictable way the following rules must be obeyed: |
| 938 | + * 1. Structural elements are retained unless the range being removed covers the entire element |
| 939 | + * 2. Elements can only be merged if they are of the same time and share a common parent |
| 940 | + * |
| 941 | + * @method |
| 942 | + * @param {es.Range} range |
| 943 | + * @returns {es.Transaction} |
| 944 | + */ |
| 945 | +/* |
| 946 | +es.DocumentModel.prototype.prepareRemovalRoan = function( range ) { |
| 947 | + var tx = new es.Transaction(), selectedNodes, selectedNode, startNode, endNode, i; |
| 948 | + range.normalize(); |
| 949 | + if ( range.start === range.end ) { |
| 950 | + // Empty range, return empty transaction |
| 951 | + return tx; |
| 952 | + } |
| 953 | + |
| 954 | + selectedNodes = this.selectNodes( range ); |
| 955 | + startNode = selectedNodes[0].node; |
| 956 | + endNode = selectedNodes[selectedNodes.length - 1].node; |
| 957 | + |
| 958 | + // If a selection is painted across two paragraphs, and then the text is deleted, the two |
| 959 | + // paragraphs can become one paragraph. However, if the selection crosses into a table, those |
| 960 | + // cannot be merged. To make this simple, we are follow a basic rule: |
| 961 | + // can merge = ( same type ) && ( same parent ) |
| 962 | + // So you can merge adjacent paragraphs, or listitems. And you can't merge a paragraph into |
| 963 | + // a table row. There may be other rules we will want in here later, for instance, special |
| 964 | + // casing merging a listitem into a paragraph. |
| 965 | + if ( startNode && endNode && |
| 966 | + startNode.getParent() === endNode.getParent() && |
| 967 | + startNode.getElementType() === endNode.getElementType() |
| 968 | + ) { |
| 969 | + // This is the simple case. node1 and node2 are either the same node, or can be merged |
| 970 | + // So we can just remove all the data in the range and call it a day, no fancy |
| 971 | + // processing necessary |
| 972 | + // FIXME we're not accounting for droppability here, should we? |
| 973 | + |
| 974 | + // Retain to the start of the range |
| 975 | + if ( range.start > 0 ) { |
| 976 | + tx.pushRetain( range.start ); |
| 977 | + } |
| 978 | + // Remove all data in a given range. |
| 979 | + tx.pushRemove( this.data.slice( range.start, range.end ) ); |
| 980 | + // Retain up to the end of the document. Why do we do this? Because Trevor said so! |
| 981 | + if ( range.end < this.data.length ) { |
| 982 | + tx.pushRetain( this.data.length - range.end ); |
| 983 | + } |
| 984 | + } else { |
| 985 | + //if ( range.start > 0 ) { |
| 986 | + // tx.pushRetain( range.start ); |
| 987 | + //} |
| 988 | + |
| 989 | + for ( i = 0; i < selectedNodes.length; i++ ) { |
| 990 | + selectedNode = selectedNodes[i]; |
| 991 | + if ( !selectedNode.range ) { |
| 992 | + // Remove the entire node |
| 993 | + // TODO accounting for droppability will suck |
| 994 | + tx.pushRemove( this.data.slice( selectedNode.globalRange.start, selectedNode.globalRange.end ) ); |
| 995 | + } else { |
| 996 | + // Remove part of the node |
| 997 | + // TODO account for droppability |
| 998 | + // TODO need to descend, rawr |
| 999 | + tx.pushRetain( 1 + selectedNode.range.start ); |
| 1000 | + if ( selectedNode.globalRange.getLength() ) { |
| 1001 | + tx.pushRemove( |
| 1002 | + this.data.slice( |
| 1003 | + selectedNode.globalRange.start, |
| 1004 | + selectedNode.globalRange.end |
| 1005 | + ) |
| 1006 | + ); |
| 1007 | + } |
| 1008 | + tx.pushRetain( selectedNode.node.getElementLength() - selectedNode.range.end - 1 ); |
| 1009 | + } |
| 1010 | + } |
| 1011 | + |
| 1012 | + // Retain up to the end of the document. Why do we do this? Because Trevor said so! |
| 1013 | + if ( range.end < this.data.length ) { |
| 1014 | + tx.pushRetain( this.data.length - range.end ); |
| 1015 | + } |
| 1016 | + } |
| 1017 | + |
| 1018 | + tx.optimize(); |
| 1019 | + return tx; |
| 1020 | +}; |
| 1021 | +*/ |
| 1022 | + |
| 1023 | +/** |
940 | 1024 | * Generates a transaction which annotates content within a given range. |
941 | 1025 | * |
942 | 1026 | * @method |