| 1239 | * Descrease the range to make sure that boundaries |
| 1240 | * always anchor beside text nodes or innermost element. |
| 1241 | * @param {Number} mode ( CKEDITOR.SHRINK_ELEMENT | CKEDITOR.SHRINK_TEXT ) The shrinking mode. |
| 1242 | */ |
| 1243 | shrink : function( mode ) |
| 1244 | { |
| 1245 | !mode && ( mode = CKEDITOR.SHRINK_TEXT ); |
| 1246 | |
| 1247 | // Unable to shrink a collapsed range. |
| 1248 | if( this.collapsed ) |
| 1249 | return false; |
| 1250 | else |
| 1251 | { |
| 1252 | var walkerRange = this.clone(); |
| 1253 | |
| 1254 | var startContainer = this.startContainer, |
| 1255 | endContainer = this.endContainer, |
| 1256 | startOffset = this.startOffset, |
| 1257 | endOffset = this.endOffset, |
| 1258 | collapsed = this.collapsed; |
| 1259 | |
| 1260 | // Whether the start/end boundary is moveable. |
| 1261 | var moveStart = 1, |
| 1262 | moveEnd = 1; |
| 1263 | |
| 1264 | if ( startContainer && startContainer.type == CKEDITOR.NODE_TEXT ) |
| 1265 | { |
| 1266 | if ( !startOffset ) |
| 1267 | walkerRange.setStartBefore( startContainer ); |
| 1268 | else if ( startOffset >= startContainer.getLength( ) ) |
| 1269 | walkerRange.setStartAfter( startContainer ); |
| 1270 | else |
| 1271 | { |
| 1272 | // Enlarge the range properly to avoid walker making |
| 1273 | // DOM changes caused by triming the text nodes later. |
| 1274 | walkerRange.setStartBefore( startContainer ); |
| 1275 | moveStart = 0; |
| 1276 | } |
| 1277 | } |
| 1278 | |
| 1279 | if ( endContainer && endContainer.type == CKEDITOR.NODE_TEXT ) |
| 1280 | { |
| 1281 | if ( !endOffset ) |
| 1282 | walkerRange.setEndBefore( endContainer ); |
| 1283 | else if ( endOffset >= endContainer.getLength( ) ) |
| 1284 | walkerRange.setEndAfter( endContainer ); |
| 1285 | else |
| 1286 | { |
| 1287 | walkerRange.setEndAfter( endContainer ); |
| 1288 | moveEnd = 0; |
| 1289 | } |
| 1290 | } |
| 1291 | |
| 1292 | var walker = new CKEDITOR.dom.walker( walkerRange ); |
| 1293 | |
| 1294 | walker.evaluator = function( node ) |
| 1295 | { |
| 1296 | return node.type == ( mode == CKEDITOR.SHRINK_ELEMENT ? |
| 1297 | CKEDITOR.NODE_ELEMENT : CKEDITOR.NODE_TEXT ); |
| 1298 | }; |
| 1299 | |
| 1300 | var currentElement; |
| 1301 | walker.guard = function( node, movingOut ) |
| 1302 | { |
| 1303 | // Stop when we're shrink in element mode while encountering a text node. |
| 1304 | if( mode == CKEDITOR.SHRINK_ELEMENT && node.type == CKEDITOR.NODE_TEXT ) |
| 1305 | return false; |
| 1306 | |
| 1307 | // Stop when we've already walked "through" an element. |
| 1308 | if ( movingOut && node.equals( currentElement ) ) |
| 1309 | return false; |
| 1310 | |
| 1311 | if ( !movingOut && node.type == CKEDITOR.NODE_ELEMENT ) |
| 1312 | currentElement = node; |
| 1313 | }; |
| 1314 | |
| 1315 | if( moveStart ) |
| 1316 | { |
| 1317 | var textStart = walker[ mode == CKEDITOR.SHRINK_ELEMENT ? 'lastForward' : 'next'](); |
| 1318 | textStart && this.setStartBefore( textStart ); |
| 1319 | } |
| 1320 | |
| 1321 | if( moveEnd ) |
| 1322 | { |
| 1323 | walker.reset(); |
| 1324 | var textEnd = walker[ mode == CKEDITOR.SHRINK_ELEMENT ? 'lastBackward' : 'previous'](); |
| 1325 | textEnd && this.setEndAfter( textEnd ); |
| 1326 | } |
| 1327 | |
| 1328 | return !!( moveStart || moveEnd ); |
| 1329 | } |
| 1330 | }, |
| 1331 | |
| 1332 | /** |