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