| | 1210 | }, |
| | 1211 | |
| | 1212 | _CheckIsParagraphBoundary : function( node ) |
| | 1213 | { |
| | 1214 | if ( node.nodeType == 1 ) |
| | 1215 | { |
| | 1216 | var tagName = node.tagName.toLowerCase() ; |
| | 1217 | return ! ( FCKListsLib.InlineNonEmptyElements[tagName] || tagName == 'img' ) ; |
| | 1218 | } |
| | 1219 | return false ; |
| | 1220 | }, |
| | 1221 | |
| | 1222 | _GenerateParagraphRange : function( paragraphList, targetWindow, startNode, endNode ) |
| | 1223 | { |
| | 1224 | if ( ! startNode || ! endNode ) |
| | 1225 | return ; |
| | 1226 | var range = new FCKDomRange( targetWindow ) ; |
| | 1227 | range._Range = new FCKW3CRange( targetWindow.document ) ; |
| | 1228 | range._Range.setStart( startNode, 0 ) ; |
| | 1229 | range._Range.setEnd( endNode, endNode.nodeType == 1 ? endNode.childNodes.length : endNode.nodeValue.length ) ; |
| | 1230 | range._UpdateElementInfo() ; |
| | 1231 | paragraphList.push( range ) ; |
| | 1232 | }, |
| | 1233 | |
| | 1234 | _GetSelectedParagraphs : function( targetWindow ) |
| | 1235 | { |
| | 1236 | var range = new FCKDomRange( targetWindow ) ; |
| | 1237 | range.MoveToSelection() ; |
| | 1238 | |
| | 1239 | var startNode = range._Range.startContainer ; |
| | 1240 | var endNode = range._Range.endContainer ; |
| | 1241 | var startOffset = range._Range.startOffset ; |
| | 1242 | var endOffset = range._Range.endOffset ; |
| | 1243 | if ( startNode.childNodes && startNode.childNodes[startOffset] ) |
| | 1244 | startNode = startNode.childNodes[startOffset] ; |
| | 1245 | if ( endNode.childNodes && endNode.childNodes[endOffset] ) |
| | 1246 | endNode = endNode.childNodes[endOffset] ; |
| | 1247 | |
| | 1248 | // Get the starting point of the selection's paragraph. |
| | 1249 | var paragraphStartNode = startNode ; |
| | 1250 | while ( paragraphStartNode ) |
| | 1251 | { |
| | 1252 | var candidate = null ; |
| | 1253 | if ( paragraphStartNode.previousSibling ) |
| | 1254 | { |
| | 1255 | if ( ! this._CheckIsParagraphBoundary( paragraphStartNode.previousSibling ) ) |
| | 1256 | candidate = paragraphStartNode.previousSibling ; |
| | 1257 | while ( candidate && candidate.lastChild && ! this._CheckIsParagraphBoundary( candidate.lastChild ) ) |
| | 1258 | candidate = candidate.lastChild ; |
| | 1259 | } |
| | 1260 | else |
| | 1261 | { |
| | 1262 | if ( ! this._CheckIsParagraphBoundary( paragraphStartNode.parentNode ) ) |
| | 1263 | candidate = paragraphStartNode.parentNode ; |
| | 1264 | } |
| | 1265 | |
| | 1266 | if ( candidate ) |
| | 1267 | paragraphStartNode = candidate ; |
| | 1268 | else |
| | 1269 | break ; |
| | 1270 | } |
| | 1271 | |
| | 1272 | // Get the ending point of the selection's paragraph. |
| | 1273 | var paragraphEndNode = endNode ; |
| | 1274 | while ( paragraphEndNode ) |
| | 1275 | { |
| | 1276 | var candidate = null ; |
| | 1277 | if ( paragraphEndNode.firstChild ) |
| | 1278 | { |
| | 1279 | if ( ! this._CheckIsParagraphBoundary( paragraphEndNode.firstChild ) ) |
| | 1280 | candidate = paragraphEndNode.firstChild ; |
| | 1281 | } |
| | 1282 | else if ( paragraphEndNode.nextSibling ) |
| | 1283 | { |
| | 1284 | if ( ! this._CheckIsParagraphBoundary( paragraphEndNode.nextSibling ) ) |
| | 1285 | candidate = paragraphEndNode.nextSibling ; |
| | 1286 | } |
| | 1287 | else |
| | 1288 | { |
| | 1289 | var ancestor = paragraphEndNode.parentNode ; |
| | 1290 | while ( ancestor ) |
| | 1291 | { |
| | 1292 | if ( this._CheckIsParagraphBoundary( ancestor ) ) |
| | 1293 | break ; |
| | 1294 | if ( ancestor.nextSibling ) |
| | 1295 | { |
| | 1296 | if ( this._CheckIsParagraphBoundary( ancestor.nextSibling ) ) |
| | 1297 | break ; |
| | 1298 | candidate = ancestor.nextSibling ; |
| | 1299 | break ; |
| | 1300 | } |
| | 1301 | else |
| | 1302 | ancestor = ancestor.parentNode ; |
| | 1303 | } |
| | 1304 | } |
| | 1305 | |
| | 1306 | if ( candidate ) |
| | 1307 | paragraphEndNode = candidate ; |
| | 1308 | else |
| | 1309 | break ; |
| | 1310 | } |
| | 1311 | |
| | 1312 | // Break up the range between paragraphStartNode and paragraphEndNode into paragraphs represented by ranges. |
| | 1313 | var retval = [] ; |
| | 1314 | var currentStart = paragraphStartNode ; |
| | 1315 | var currentEnd = currentStart ; |
| | 1316 | |
| | 1317 | // Each iteration advances the position by one node in a DFS tree walk. |
| | 1318 | while ( currentEnd != paragraphEndNode ) |
| | 1319 | { |
| | 1320 | // 1. if we come across a <br> node, save a new paragraph |
| | 1321 | // 2. if we come across a block element boundary, save a new paragraph |
| | 1322 | // 3. set currentStart to null after saving a new paragraph |
| | 1323 | // 4. set currentStart to currentEnd if currentStart is null and currentEnd is not boundary node |
| | 1324 | if ( currentStart == null && currentEnd.nodeType == 3 ) |
| | 1325 | { |
| | 1326 | // Ignore normal whitespaces (i.e. not including or other unicode whitespaces) after a block node. |
| | 1327 | if ( currentEnd.nodeValue.search( /^[\r\n\t ]*$/ ) == 0 ) |
| | 1328 | { |
| | 1329 | var prevNode = currentEnd.previousSibling ; |
| | 1330 | if ( prevNode ) |
| | 1331 | { |
| | 1332 | var prevTag = String( prevNode.tagName ).toLowerCase() ; |
| | 1333 | if ( ! ( FCKListsLib.BlockElements[prevTag] || FCKListsLib.NonEmptyBlockElements[prevTag] ) ) |
| | 1334 | currentStart = currentEnd ; |
| | 1335 | } |
| | 1336 | } |
| | 1337 | else |
| | 1338 | currentStart = currentEnd ; |
| | 1339 | } |
| | 1340 | |
| | 1341 | if ( currentEnd.firstChild ) |
| | 1342 | { |
| | 1343 | if ( this._CheckIsParagraphBoundary( currentEnd.firstChild ) ) |
| | 1344 | { |
| | 1345 | this._GenerateParagraphRange( retval, targetWindow, currentStart, currentEnd ) ; |
| | 1346 | currentStart = null ; |
| | 1347 | } |
| | 1348 | currentEnd = currentEnd.firstChild ; |
| | 1349 | } |
| | 1350 | else if ( currentEnd.nextSibling ) |
| | 1351 | { |
| | 1352 | if ( this._CheckIsParagraphBoundary( currentEnd.nextSibling ) ) |
| | 1353 | { |
| | 1354 | this._GenerateParagraphRange( retval, targetWindow, currentStart, currentEnd ) ; |
| | 1355 | currentStart = null ; |
| | 1356 | } |
| | 1357 | currentEnd = currentEnd.nextSibling ; |
| | 1358 | } |
| | 1359 | else |
| | 1360 | { |
| | 1361 | var ancestor = currentEnd.parentNode ; |
| | 1362 | while ( ancestor ) |
| | 1363 | { |
| | 1364 | if ( this._CheckIsParagraphBoundary( ancestor ) ) |
| | 1365 | { |
| | 1366 | this._GenerateParagraphRange( retval, targetWindow, currentStart, currentEnd ) ; |
| | 1367 | currentStart = null ; |
| | 1368 | } |
| | 1369 | if ( ancestor.nextSibling ) |
| | 1370 | { |
| | 1371 | if ( this._CheckIsParagraphBoundary( ancestor.nextSibling ) ) |
| | 1372 | { |
| | 1373 | this._GenerateParagraphRange( retval, targetWindow, currentStart, currentEnd ) ; |
| | 1374 | currentStart = null ; |
| | 1375 | } |
| | 1376 | currentEnd = ancestor.nextSibling ; |
| | 1377 | break ; |
| | 1378 | } |
| | 1379 | else |
| | 1380 | ancestor = ancestor.parentNode ; |
| | 1381 | } |
| | 1382 | } |
| | 1383 | } |
| | 1384 | // Record the final range as well. |
| | 1385 | if ( currentStart == null && currentEnd.nodeType == 3 ) |
| | 1386 | currentStart = currentEnd ; |
| | 1387 | this._GenerateParagraphRange( retval, targetWindow, currentStart, currentEnd ) ; |
| | 1388 | |
| | 1389 | return retval ; |