| 697 | |
| 698 | // Registering keydown delete/backspace key handling logic. |
| 699 | editor.on( 'contentDom', function() |
| 700 | { |
| 701 | editor.document.on( 'keydown', function( evt ) |
| 702 | { |
| 703 | var keyCode = evt.data.getKeystroke(); |
| 704 | |
| 705 | // Backspace or Delete. |
| 706 | if ( keyCode in { 8 : 1, 46 : 1 } ) |
| 707 | { |
| 708 | var range = editor.getSelection().getRanges()[ 0 ], |
| 709 | block = new CKEDITOR.dom.elementPath( range.startContainer ).block, |
| 710 | li; |
| 711 | |
| 712 | if ( range.collapsed && ( li = block.getAscendant( 'li', true ) ) ) |
| 713 | { |
| 714 | function moveListItem( source, target ) |
| 715 | { |
| 716 | editor.fire( 'saveSnapshot' ); |
| 717 | |
| 718 | var sourceLast = source.getLast(), |
| 719 | targetLast = target.getLast(); |
| 720 | |
| 721 | // In Gecko, the last child node is <br>. |
| 722 | if ( CKEDITOR.env.gecko ) |
| 723 | { |
| 724 | sourceLast && sourceLast.is && sourceLast.is( 'br' ) && sourceLast.remove(); |
| 725 | targetLast && targetLast.is && targetLast.is( 'br' ) && targetLast.remove(); |
| 726 | } |
| 727 | |
| 728 | if ( target.is && target.is( 'body' ) ) |
| 729 | { |
| 730 | source.moveChildren( target, true ); |
| 731 | range.moveToPosition( target, CKEDITOR.POSITION_AFTER_START ); |
| 732 | } |
| 733 | else |
| 734 | { |
| 735 | var innerTarget = |
| 736 | targetLast && targetLast.is && targetLast.is( 'p', 'div' ) ? |
| 737 | targetLast : target; |
| 738 | |
| 739 | range.moveToElementEditEnd( innerTarget ); |
| 740 | |
| 741 | var sourceFirstChild = source.getChild( 0 ); |
| 742 | if ( source.getChildCount() == 1 ) |
| 743 | { |
| 744 | var innerSource = |
| 745 | sourceFirstChild.is && sourceFirstChild.is( 'p', 'div' ) ? |
| 746 | sourceFirstChild : source; |
| 747 | |
| 748 | innerSource.moveChildren( innerTarget ); |
| 749 | } |
| 750 | else if ( source.getChildCount() > 1 ) |
| 751 | { |
| 752 | var innerFirst = |
| 753 | sourceFirstChild.is && sourceFirstChild.is( 'p', 'div' ) ? |
| 754 | sourceFirstChild.getFirst() : sourceFirstChild; |
| 755 | |
| 756 | innerTarget.append( innerFirst ); |
| 757 | sourceFirstChild.remove(); |
| 758 | source.moveChildren( target ); |
| 759 | } |
| 760 | } |
| 761 | |
| 762 | source.remove(); |
| 763 | range.select(); |
| 764 | evt.data.preventDefault(); |
| 765 | } |
| 766 | |
| 767 | // Backspace |
| 768 | if ( keyCode == 8 && range.checkStartOfBlock() && !block.getPrevious() ) |
| 769 | { |
| 770 | var previous; |
| 771 | |
| 772 | // Previous element is item of the same list. |
| 773 | if ( ( previous = li.getPrevious() ) && previous.is && previous.is( 'li' ) ) |
| 774 | { |
| 775 | moveListItem( li, previous ); |
| 776 | } |
| 777 | else |
| 778 | { |
| 779 | var currentList = li.getParent(); |
| 780 | |
| 781 | // Previous element doesn't exist (curent list item is first item in editor area). |
| 782 | if ( !currentList.getPrevious() ) |
| 783 | { |
| 784 | moveListItem( li, range.document.getBody() ); |
| 785 | } |
| 786 | // Previous element is some block before list. |
| 787 | else |
| 788 | { |
| 789 | range.setStartAt( currentList.getParent(), CKEDITOR.POSITION_AFTER_START ); |
| 790 | range.setEndAt( currentList, CKEDITOR.POSITION_AFTER_START ); |
| 791 | |
| 792 | var walker = new CKEDITOR.dom.walker( range ); |
| 793 | while ( previous = walker.next() ) |
| 794 | { |
| 795 | if ( previous.getNext() && previous.getNext().equals( currentList ) ) |
| 796 | { |
| 797 | moveListItem( li, previous ); |
| 798 | break; |
| 799 | } |
| 800 | } |
| 801 | } |
| 802 | |
| 803 | if ( currentList.getChildCount() == 0 ) |
| 804 | currentList.remove(); |
| 805 | } |
| 806 | } |
| 807 | // Delete |
| 808 | else if ( keyCode == 46 ) |
| 809 | { |
| 810 | var sublist = li.getFirst( function( node ){ return node.is && node.is( 'ol', 'ul' ); } ); |
| 811 | |
| 812 | // Check if cursor (range) is set in the end of current list item. |
| 813 | // If list item doesn't contain any sublist we can use range::checkEndOfBlock() function. |
| 814 | // If list item contains sublist, we have to use walker to find if the next element is sublist. |
| 815 | if ( !range.checkEndOfBlock() ) |
| 816 | { |
| 817 | if ( sublist ) |
| 818 | { |
| 819 | var walkerRange = range.clone(); |
| 820 | walkerRange.setEndAt( sublist, CKEDITOR.POSITION_AFTER_START ); |
| 821 | |
| 822 | var walker = new CKEDITOR.dom.walker( walkerRange ); |
| 823 | walker.evaluator = function( node ) |
| 824 | { |
| 825 | if ( CKEDITOR.env.gecko && node.is && node.is( 'br' ) && node.getNext().is && node.getNext().is( 'ul' ) ) |
| 826 | return false; |
| 827 | } |
| 828 | |
| 829 | if ( !walker.next().equals( sublist ) ) |
| 830 | return; |
| 831 | } |
| 832 | else |
| 833 | return; |
| 834 | } |
| 835 | |
| 836 | var next; |
| 837 | |
| 838 | // Next element is item of the same list. |
| 839 | if ( !sublist && ( next = li.getNext() ) ) |
| 840 | { |
| 841 | moveListItem( next, li ); |
| 842 | } |
| 843 | // Next element is item of sublist |
| 844 | else if ( sublist && ( next = sublist.getFirst( function( node ) { return node.is( 'li' ) } ) ) ) |
| 845 | { |
| 846 | range.setStartAt( li, CKEDITOR.POSITION_AFTER_START ); |
| 847 | |
| 848 | var walker = new CKEDITOR.dom.walker( range ), |
| 849 | currentBlock; |
| 850 | |
| 851 | while ( currentBlock = walker.next() ) |
| 852 | { |
| 853 | var item = currentBlock.getNext(); |
| 854 | |
| 855 | if ( CKEDITOR.env.gecko && item.is && item.is( 'br' ) && item.getNext() && item.getNext().equals( sublist ) || |
| 856 | item && item.equals( sublist ) ) |
| 857 | { |
| 858 | moveListItem( next, currentBlock ); |
| 859 | break; |
| 860 | } |
| 861 | } |
| 862 | |
| 863 | if ( sublist.getChildCount() == 0 ) |
| 864 | sublist.remove(); |
| 865 | } |
| 866 | } |
| 867 | } |
| 868 | } |
| 869 | }); |
| 870 | }); |