aboutsummaryrefslogtreecommitdiff
path: root/sources/plugins/link/dialogs
diff options
context:
space:
mode:
Diffstat (limited to 'sources/plugins/link/dialogs')
-rw-r--r--sources/plugins/link/dialogs/anchor.js27
-rw-r--r--sources/plugins/link/dialogs/link.js202
2 files changed, 141 insertions, 88 deletions
diff --git a/sources/plugins/link/dialogs/anchor.js b/sources/plugins/link/dialogs/anchor.js
index 2b32b71..04a4abe 100644
--- a/sources/plugins/link/dialogs/anchor.js
+++ b/sources/plugins/link/dialogs/anchor.js
@@ -18,6 +18,21 @@ CKEDITOR.dialog.add( 'anchor', function( editor ) {
18 } ), 'cke_anchor', 'anchor' ); 18 } ), 'cke_anchor', 'anchor' );
19 } 19 }
20 20
21
22 function getSelectedAnchor( selection ) {
23 var range = selection.getRanges()[ 0 ],
24 element = selection.getSelectedElement();
25
26 // In case of table cell selection, we want to shrink selection from td to a element.
27 range.shrink( CKEDITOR.SHRINK_ELEMENT );
28 element = range.getEnclosedNode();
29
30 if ( element && element.type === CKEDITOR.NODE_ELEMENT &&
31 ( element.data( 'cke-real-element-type' ) === 'anchor' || element.is( 'a' ) ) ) {
32 return element;
33 }
34 }
35
21 return { 36 return {
22 title: editor.lang.link.anchor.title, 37 title: editor.lang.link.anchor.title,
23 minWidth: 300, 38 minWidth: 300,
@@ -35,9 +50,10 @@ CKEDITOR.dialog.add( 'anchor', function( editor ) {
35 var newFake = createFakeAnchor( editor, attributes ); 50 var newFake = createFakeAnchor( editor, attributes );
36 newFake.replace( this._.selectedElement ); 51 newFake.replace( this._.selectedElement );
37 52
38 // Selecting fake element for IE. (#11377) 53 // Selecting fake element for IE. (http://dev.ckeditor.com/ticket/11377)
39 if ( CKEDITOR.env.ie ) 54 if ( CKEDITOR.env.ie ) {
40 editor.getSelection().selectElement( newFake ); 55 editor.getSelection().selectElement( newFake );
56 }
41 } else { 57 } else {
42 this._.selectedElement.setAttributes( attributes ); 58 this._.selectedElement.setAttributes( attributes );
43 } 59 }
@@ -56,7 +72,7 @@ CKEDITOR.dialog.add( 'anchor', function( editor ) {
56 // Apply style. 72 // Apply style.
57 var style = new CKEDITOR.style( { element: 'a', attributes: attributes } ); 73 var style = new CKEDITOR.style( { element: 'a', attributes: attributes } );
58 style.type = CKEDITOR.STYLE_INLINE; 74 style.type = CKEDITOR.STYLE_INLINE;
59 editor.applyStyle( style ); 75 style.applyToRange( range );
60 } 76 }
61 } 77 }
62 }, 78 },
@@ -67,7 +83,7 @@ CKEDITOR.dialog.add( 'anchor', function( editor ) {
67 83
68 onShow: function() { 84 onShow: function() {
69 var sel = editor.getSelection(), 85 var sel = editor.getSelection(),
70 fullySelected = sel.getSelectedElement(), 86 fullySelected = getSelectedAnchor( sel ),
71 fakeSelected = fullySelected && fullySelected.data( 'cke-realelement' ), 87 fakeSelected = fullySelected && fullySelected.data( 'cke-realelement' ),
72 linkElement = fakeSelected ? 88 linkElement = fakeSelected ?
73 CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, fullySelected ) : 89 CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, fullySelected ) :
@@ -77,8 +93,9 @@ CKEDITOR.dialog.add( 'anchor', function( editor ) {
77 loadElements.call( this, linkElement ); 93 loadElements.call( this, linkElement );
78 !fakeSelected && sel.selectElement( linkElement ); 94 !fakeSelected && sel.selectElement( linkElement );
79 95
80 if ( fullySelected ) 96 if ( fullySelected ) {
81 this._.selectedElement = fullySelected; 97 this._.selectedElement = fullySelected;
98 }
82 } 99 }
83 100
84 this.getContentElement( 'info', 'txtName' ).focus(); 101 this.getContentElement( 'info', 'txtName' ).focus();
diff --git a/sources/plugins/link/dialogs/link.js b/sources/plugins/link/dialogs/link.js
index 914471f..4c60928 100644
--- a/sources/plugins/link/dialogs/link.js
+++ b/sources/plugins/link/dialogs/link.js
@@ -10,6 +10,110 @@
10 var plugin = CKEDITOR.plugins.link, 10 var plugin = CKEDITOR.plugins.link,
11 initialLinkText; 11 initialLinkText;
12 12
13 function createRangeForLink( editor, link ) {
14 var range = editor.createRange();
15
16 range.setStartBefore( link );
17 range.setEndAfter( link );
18
19 return range;
20 }
21
22 function insertLinksIntoSelection( editor, data ) {
23 var attributes = plugin.getLinkAttributes( editor, data ),
24 ranges = editor.getSelection().getRanges(),
25 style = new CKEDITOR.style( {
26 element: 'a',
27 attributes: attributes.set
28 } ),
29 rangesToSelect = [],
30 range,
31 text,
32 nestedLinks,
33 i,
34 j;
35
36 style.type = CKEDITOR.STYLE_INLINE; // need to override... dunno why.
37
38 for ( i = 0; i < ranges.length; i++ ) {
39 range = ranges[ i ];
40
41 // Use link URL as text with a collapsed cursor.
42 if ( range.collapsed ) {
43 // Short mailto link text view (http://dev.ckeditor.com/ticket/5736).
44 text = new CKEDITOR.dom.text( data.linkText || ( data.type == 'email' ?
45 data.email.address : attributes.set[ 'data-cke-saved-href' ] ), editor.document );
46 range.insertNode( text );
47 range.selectNodeContents( text );
48 } else if ( initialLinkText !== data.linkText ) {
49 text = new CKEDITOR.dom.text( data.linkText, editor.document );
50
51 // Shrink range to preserve block element.
52 range.shrink( CKEDITOR.SHRINK_TEXT );
53
54 // Use extractHtmlFromRange to remove markup within the selection. Also this method is a little
55 // smarter than range#deleteContents as it plays better e.g. with table cells.
56 editor.editable().extractHtmlFromRange( range );
57
58 range.insertNode( text );
59 }
60
61 // Editable links nested within current range should be removed, so that the link is applied to whole selection.
62 nestedLinks = range._find( 'a' );
63
64 for ( j = 0; j < nestedLinks.length; j++ ) {
65 nestedLinks[ j ].remove( true );
66 }
67
68
69 // Apply style.
70 style.applyToRange( range, editor );
71
72 rangesToSelect.push( range );
73 }
74
75 editor.getSelection().selectRanges( rangesToSelect );
76 }
77
78 function editLinksInSelection( editor, selectedElements, data ) {
79 var attributes = plugin.getLinkAttributes( editor, data ),
80 ranges = [],
81 element,
82 href,
83 textView,
84 newText,
85 i;
86
87 for ( i = 0; i < selectedElements.length; i++ ) {
88 // We're only editing an existing link, so just overwrite the attributes.
89 element = selectedElements[ i ];
90 href = element.data( 'cke-saved-href' );
91 textView = element.getHtml();
92
93 element.setAttributes( attributes.set );
94 element.removeAttributes( attributes.removed );
95
96
97 if ( data.linkText && initialLinkText != data.linkText ) {
98 // Display text has been changed.
99 newText = data.linkText;
100 } else if ( href == textView || data.type == 'email' && textView.indexOf( '@' ) != -1 ) {
101 // Update text view when user changes protocol (http://dev.ckeditor.com/ticket/4612).
102 // Short mailto link text view (http://dev.ckeditor.com/ticket/5736).
103 newText = data.type == 'email' ? data.email.address : attributes.set[ 'data-cke-saved-href' ];
104 }
105
106 if ( newText ) {
107 element.setText( newText );
108 }
109
110 ranges.push( createRangeForLink( editor, element ) );
111 }
112
113 // We changed the content, so need to select it again.
114 editor.getSelection().selectRanges( ranges );
115 }
116
13 // Handles the event when the "Target" selection box is changed. 117 // Handles the event when the "Target" selection box is changed.
14 var targetChanged = function() { 118 var targetChanged = function() {
15 var dialog = this.getDialog(), 119 var dialog = this.getDialog(),
@@ -163,7 +267,7 @@
163 label: commonLang.protocol, 267 label: commonLang.protocol,
164 'default': 'http://', 268 'default': 'http://',
165 items: [ 269 items: [
166 // Force 'ltr' for protocol names in BIDI. (#5433) 270 // Force 'ltr' for protocol names in BIDI. (http://dev.ckeditor.com/ticket/5433)
167 [ 'http://\u200E', 'http://' ], 271 [ 'http://\u200E', 'http://' ],
168 [ 'https://\u200E', 'https://' ], 272 [ 'https://\u200E', 'https://' ],
169 [ 'ftp://\u200E', 'ftp://' ], 273 [ 'ftp://\u200E', 'ftp://' ],
@@ -236,7 +340,7 @@
236 }, 340 },
237 commit: function( data ) { 341 commit: function( data ) {
238 // IE will not trigger the onChange event if the mouse has been used 342 // IE will not trigger the onChange event if the mouse has been used
239 // to carry all the operations #4724 343 // to carry all the operations http://dev.ckeditor.com/ticket/4724
240 this.onChange(); 344 this.onChange();
241 345
242 if ( !data.url ) 346 if ( !data.url )
@@ -819,33 +923,30 @@
819 onShow: function() { 923 onShow: function() {
820 var editor = this.getParentEditor(), 924 var editor = this.getParentEditor(),
821 selection = editor.getSelection(), 925 selection = editor.getSelection(),
822 selectedElement = selection.getSelectedElement(),
823 displayTextField = this.getContentElement( 'info', 'linkDisplayText' ).getElement().getParent().getParent(), 926 displayTextField = this.getContentElement( 'info', 'linkDisplayText' ).getElement().getParent().getParent(),
824 element = null; 927 elements = plugin.getSelectedLink( editor, true ),
928 firstLink = elements[ 0 ] || null;
825 929
826 // Fill in all the relevant fields if there's already one link selected. 930 // Fill in all the relevant fields if there's already one link selected.
827 if ( ( element = plugin.getSelectedLink( editor ) ) && element.hasAttribute( 'href' ) ) { 931 if ( firstLink && firstLink.hasAttribute( 'href' ) ) {
828 // Don't change selection if some element is already selected. 932 // Don't change selection if some element is already selected.
829 // For example - don't destroy fake selection. 933 // For example - don't destroy fake selection.
830 if ( !selectedElement ) { 934 if ( !selection.getSelectedElement() && !selection.isInTable() ) {
831 selection.selectElement( element ); 935 selection.selectElement( firstLink );
832 selectedElement = element;
833 } 936 }
834 } else {
835 element = null;
836 } 937 }
837 938
939 var data = plugin.parseLinkAttributes( editor, firstLink );
940
838 // Here we'll decide whether or not we want to show Display Text field. 941 // Here we'll decide whether or not we want to show Display Text field.
839 if ( plugin.showDisplayTextForElement( selectedElement, editor ) ) { 942 if ( elements.length <= 1 && plugin.showDisplayTextForElement( firstLink, editor ) ) {
840 displayTextField.show(); 943 displayTextField.show();
841 } else { 944 } else {
842 displayTextField.hide(); 945 displayTextField.hide();
843 } 946 }
844 947
845 var data = plugin.parseLinkAttributes( editor, element );
846
847 // Record down the selected element in the dialog. 948 // Record down the selected element in the dialog.
848 this._.selectedElement = element; 949 this._.selectedElements = elements;
849 950
850 this.setupContent( data ); 951 this.setupContent( data );
851 }, 952 },
@@ -855,77 +956,12 @@
855 // Collect data from fields. 956 // Collect data from fields.
856 this.commitContent( data ); 957 this.commitContent( data );
857 958
858 var selection = editor.getSelection(), 959 if ( !this._.selectedElements.length ) {
859 attributes = plugin.getLinkAttributes( editor, data ), 960 insertLinksIntoSelection( editor, data );
860 bm,
861 nestedLinks;
862
863 if ( !this._.selectedElement ) {
864 var range = selection.getRanges()[ 0 ],
865 text;
866
867 // Use link URL as text with a collapsed cursor.
868 if ( range.collapsed ) {
869 // Short mailto link text view (#5736).
870 text = new CKEDITOR.dom.text( data.linkText || ( data.type == 'email' ?
871 data.email.address : attributes.set[ 'data-cke-saved-href' ] ), editor.document );
872 range.insertNode( text );
873 range.selectNodeContents( text );
874 } else if ( initialLinkText !== data.linkText ) {
875 text = new CKEDITOR.dom.text( data.linkText, editor.document );
876
877 // Shrink range to preserve block element.
878 range.shrink( CKEDITOR.SHRINK_TEXT );
879
880 // Use extractHtmlFromRange to remove markup within the selection. Also this method is a little
881 // smarter than range#deleteContents as it plays better e.g. with table cells.
882 editor.editable().extractHtmlFromRange( range );
883
884 range.insertNode( text );
885 }
886
887 // Editable links nested within current range should be removed, so that the link is applied to whole selection.
888 nestedLinks = range._find( 'a' );
889
890 for ( var i = 0; i < nestedLinks.length; i++ ) {
891 nestedLinks[ i ].remove( true );
892 }
893
894 // Apply style.
895 var style = new CKEDITOR.style( {
896 element: 'a',
897 attributes: attributes.set
898 } );
899
900 style.type = CKEDITOR.STYLE_INLINE; // need to override... dunno why.
901 style.applyToRange( range, editor );
902 range.select();
903 } else { 961 } else {
904 // We're only editing an existing link, so just overwrite the attributes. 962 editLinksInSelection( editor, this._.selectedElements, data );
905 var element = this._.selectedElement,
906 href = element.data( 'cke-saved-href' ),
907 textView = element.getHtml(),
908 newText;
909
910 element.setAttributes( attributes.set );
911 element.removeAttributes( attributes.removed );
912
913 if ( data.linkText && initialLinkText != data.linkText ) {
914 // Display text has been changed.
915 newText = data.linkText;
916 } else if ( href == textView || data.type == 'email' && textView.indexOf( '@' ) != -1 ) {
917 // Update text view when user changes protocol (#4612).
918 // Short mailto link text view (#5736).
919 newText = data.type == 'email' ? data.email.address : attributes.set[ 'data-cke-saved-href' ];
920 }
921
922 if ( newText ) {
923 element.setText( newText );
924 // We changed the content, so need to select it again.
925 selection.selectElement( element );
926 }
927 963
928 delete this._.selectedElement; 964 delete this._.selectedElements;
929 } 965 }
930 }, 966 },
931 onLoad: function() { 967 onLoad: function() {