| | 453 | // In order to prevent triggering the IE bug mentioned below, we will try to |
| | 454 | // optimize by not restoring the selection if it happens to match the current |
| | 455 | // selection. |
| | 456 | var range = this.createRange(this.getSelection()); |
| | 457 | |
| | 458 | // We can't compare two selections that come from different documents, so we |
| | 459 | // must make sure they're from the same document. |
| | 460 | var findDoc = function(el) |
| | 461 | { |
| | 462 | for (var root=el; root; root=root.parentNode) |
| | 463 | { |
| | 464 | if (root.tagName.toLowerCase() == 'html') |
| | 465 | { |
| | 466 | return root.parentNode; |
| | 467 | } |
| | 468 | } |
| | 469 | return null; |
| | 470 | } |
| | 471 | |
| | 472 | if (findDoc(savedSelection.parentElement()) == findDoc(range.parentElement())) |
| | 473 | { |
| | 474 | if ((0 == range.compareEndPoints('StartToStart',savedSelection)) && |
| | 475 | (0 == range.compareEndPoints('EndToEnd',savedSelection))) |
| | 476 | { |
| | 477 | // The selection hasn't moved, no need to restore. |
| | 478 | return; |
| | 479 | } |
| | 480 | } |
| | 481 | |
| | 483 | range = this.createRange(this.getSelection()); |
| | 484 | if (range.parentElement() != savedSelection.parentElement()) |
| | 485 | { |
| | 486 | // IE has a problem with selections at the end of text nodes that |
| | 487 | // immediately precede block nodes. Example markup: |
| | 488 | // <div>Text Node<p>Text in Block</p></div> |
| | 489 | // ^ |
| | 490 | // The problem occurs when the cursor is after the 'e' in Node. |
| | 491 | |
| | 492 | var solution = editor.config.selectWorkaround || 'InsertSpan'; |
| | 493 | switch (solution) |
| | 494 | { |
| | 495 | case 'SimulateClick': |
| | 496 | // Try to get the bounding box of the selection and then simulate a |
| | 497 | // mouse click in the upper right corner to return the cursor to the |
| | 498 | // correct location. |
| | 499 | |
| | 500 | // No code yet, fall through to InsertSpan |
| | 501 | case 'InsertSpan': |
| | 502 | // This workaround inserts an empty span element so that we are no |
| | 503 | // longer trying to select a text node, |
| | 504 | var parentDoc = findDoc(savedSelection.parentElement()); |
| | 505 | |
| | 506 | // A function used to generate a unique ID for our temporary span. |
| | 507 | var randLetters = function(count) |
| | 508 | { |
| | 509 | // Build a list of 26 letters. |
| | 510 | var Letters = ''; |
| | 511 | for (var index = 0; index<26; ++index) |
| | 512 | { |
| | 513 | Letters += String.fromCharCode('a'.charCodeAt(0) + index); |
| | 514 | } |
| | 515 | |
| | 516 | var result = ''; |
| | 517 | for (var index=0; index<count; ++index) |
| | 518 | { |
| | 519 | result += Letters.substr(Math.floor(Math.random()*26 + 1), 1); |
| | 520 | } |
| | 521 | return result; |
| | 522 | } |
| | 523 | |
| | 524 | // We'll try to find a unique ID to use for finding our element. |
| | 525 | var keyLength = 1; |
| | 526 | var tempId = '__InsertSpan_Workaround_' + randLetters(keyLength); |
| | 527 | while (parentDoc.getElementById(tempId)) |
| | 528 | { |
| | 529 | // Each time there's a collision, we'll increase our key length by |
| | 530 | // one, making the chances of a collision exponentially more rare. |
| | 531 | keyLength += 1; |
| | 532 | tempId = '__InsertSpan_Workaround_' + randLetters(keyLength); |
| | 533 | } |
| | 534 | |
| | 535 | // Now that we have a uniquely identifiable element, we'll stick it and |
| | 536 | // and use it to orient our selection. |
| | 537 | savedSelection.pasteHTML('<span id="' + tempId + '"></span>'); |
| | 538 | var tempSpan = parentDoc.getElementById(tempId); |
| | 539 | savedSelection.moveToElementText(tempSpan); |
| | 540 | savedSelection.select(); |
| | 541 | break; |
| | 542 | case 'JustificationHack': |
| | 543 | // Setting the justification on an element causes IE to alter the |
| | 544 | // markup so that the selection we want to make is possible. |
| | 545 | // Unfortunately, this can force block elements to be kicked out of |
| | 546 | // their containing element, so it is not recommended. |
| | 547 | |
| | 548 | // Set a non-valid character and use it to anchor our selection. |
| | 549 | var magicString = String.fromCharCode(1); |
| | 550 | savedSelection.pasteHTML(magicString); |
| | 551 | savedSelection.findText(magicString,-1); |
| | 552 | savedSelection.select(); |
| | 553 | |
| | 554 | // I don't know how to find out if there's an existing justification on |
| | 555 | // this element. Hopefully, you're doing all of your styling outside, |
| | 556 | // so I'll just clear. I already told you this was a hack. |
| | 557 | savedSelection.execCommand('JustifyNone'); |
| | 558 | savedSelection.pasteHTML(''); |
| | 559 | break; |
| | 560 | case 'VisiblePrompt': |
| | 561 | default: |
| | 562 | // This method will insert a little box character to hold our selection |
| | 563 | // in the desired spot. We're depending on the user to see this ugly |
| | 564 | // box and delete it themselves. |
| | 565 | var magicString = String.fromCharCode(1); |
| | 566 | savedSelection.pasteHTML(magicString); |
| | 567 | savedSelection.findText(magicString,-1); |
| | 568 | savedSelection.select(); |
| | 569 | } |
| | 570 | } |