aboutsummaryrefslogtreecommitdiff
path: root/sources/plugins/link
diff options
context:
space:
mode:
Diffstat (limited to 'sources/plugins/link')
-rw-r--r--sources/plugins/link/dialogs/anchor.js27
-rw-r--r--sources/plugins/link/dialogs/link.js202
-rw-r--r--sources/plugins/link/lang/eo.js4
-rw-r--r--sources/plugins/link/lang/es-mx.js67
-rw-r--r--sources/plugins/link/lang/fr.js4
-rw-r--r--sources/plugins/link/lang/gl.js4
-rw-r--r--sources/plugins/link/lang/hr.js16
-rw-r--r--sources/plugins/link/lang/hu.js4
-rw-r--r--sources/plugins/link/lang/ja.js4
-rw-r--r--sources/plugins/link/lang/ko.js4
-rw-r--r--sources/plugins/link/lang/ku.js4
-rw-r--r--sources/plugins/link/lang/ru.js2
-rw-r--r--sources/plugins/link/lang/sk.js4
-rw-r--r--sources/plugins/link/lang/zh.js2
-rw-r--r--sources/plugins/link/plugin.js104
15 files changed, 310 insertions, 142 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() {
diff --git a/sources/plugins/link/lang/eo.js b/sources/plugins/link/lang/eo.js
index 7991231..d2b6faf 100644
--- a/sources/plugins/link/lang/eo.js
+++ b/sources/plugins/link/lang/eo.js
@@ -19,8 +19,8 @@ CKEDITOR.plugins.setLang( 'link', 'eo', {
19 anchorName: 'Per Ankronomo', 19 anchorName: 'Per Ankronomo',
20 charset: 'Signaro de la Ligita Rimedo', 20 charset: 'Signaro de la Ligita Rimedo',
21 cssClasses: 'Klasoj de Stilfolioj', 21 cssClasses: 'Klasoj de Stilfolioj',
22 download: 'Force Download', // MISSING 22 download: 'Altrudi Elŝuton',
23 displayText: 'Display Text', // MISSING 23 displayText: 'Vidigi Tekston',
24 emailAddress: 'Retpoŝto', 24 emailAddress: 'Retpoŝto',
25 emailBody: 'Mesaĝa korpo', 25 emailBody: 'Mesaĝa korpo',
26 emailSubject: 'Mesaĝa Temo', 26 emailSubject: 'Mesaĝa Temo',
diff --git a/sources/plugins/link/lang/es-mx.js b/sources/plugins/link/lang/es-mx.js
new file mode 100644
index 0000000..1c27060
--- /dev/null
+++ b/sources/plugins/link/lang/es-mx.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'es-mx', {
6 acccessKey: 'Llave de acceso',
7 advanced: 'Avanzada',
8 advisoryContentType: 'Tipo de contenido consultivo',
9 advisoryTitle: 'Título asesor',
10 anchor: {
11 toolbar: 'Ancla',
12 menu: 'Editar ancla',
13 title: 'Propiedades del ancla',
14 name: 'Nombre del ancla',
15 errorName: 'Escriba el nombre del ancla',
16 remove: 'Remover ancla'
17 },
18 anchorId: 'Por Id del elemento',
19 anchorName: 'Por nombre del ancla',
20 charset: 'Recurso relacionado Charset',
21 cssClasses: 'Clases de estilo de hoja',
22 download: 'Forzar la descarga',
23 displayText: 'Mostrar texto',
24 emailAddress: 'Dirección de correo electrónico',
25 emailBody: 'Cuerpo del mensaje',
26 emailSubject: 'Asunto del mensaje',
27 id: 'Id',
28 info: 'Información del enlace',
29 langCode: 'Código del idioma',
30 langDir: 'Dirección del idioma',
31 langDirLTR: 'Izquierda a Derecha (LTR)',
32 langDirRTL: 'Derecha a Izquierda (RTL)',
33 menu: 'Editar enlace',
34 name: 'Nombre',
35 noAnchors: '(No hay anclas disponibles en el documento)',
36 noEmail: 'Escriba la dirección de correo electrónico',
37 noUrl: 'Escriba la URL del enlace',
38 other: '<other>',
39 popupDependent: 'Dependiente (Netscape)',
40 popupFeatures: 'Ventana emergente',
41 popupFullScreen: 'Pantalla completa (IE)',
42 popupLeft: 'Posición Izquierda',
43 popupLocationBar: 'Ubicación de la barra',
44 popupMenuBar: 'Barra de menú',
45 popupResizable: 'Redimensionable',
46 popupScrollBars: 'Barras de desplazamiento',
47 popupStatusBar: 'Barra de estado',
48 popupToolbar: 'Barra de herramienta',
49 popupTop: 'Posición superior',
50 rel: 'Relación',
51 selectAnchor: 'Selecciona un ancla',
52 styles: 'Estilo',
53 tabIndex: 'Indice de tabulación',
54 target: 'Objetivo',
55 targetFrame: '<frame>',
56 targetFrameName: 'Nombre del marco de destino',
57 targetPopup: '<popup window>',
58 targetPopupName: 'Nombre de ventana emergente',
59 title: 'Enlace',
60 toAnchor: 'Enlace al ancla en el texto',
61 toEmail: 'Correo electrónico',
62 toUrl: 'URL',
63 toolbar: 'Enlace',
64 type: 'Tipo de enlace',
65 unlink: 'Desconectar',
66 upload: 'Subir'
67} );
diff --git a/sources/plugins/link/lang/fr.js b/sources/plugins/link/lang/fr.js
index a4561cb..d40d8d9 100644
--- a/sources/plugins/link/lang/fr.js
+++ b/sources/plugins/link/lang/fr.js
@@ -19,8 +19,8 @@ CKEDITOR.plugins.setLang( 'link', 'fr', {
19 anchorName: 'Par nom d\'ancre', 19 anchorName: 'Par nom d\'ancre',
20 charset: 'Encodage de la ressource liée', 20 charset: 'Encodage de la ressource liée',
21 cssClasses: 'Classes de style', 21 cssClasses: 'Classes de style',
22 download: 'Force Download', // MISSING 22 download: 'Forcer le téléchargement',
23 displayText: 'Display Text', // MISSING 23 displayText: 'Afficher le texte',
24 emailAddress: 'Adresse électronique', 24 emailAddress: 'Adresse électronique',
25 emailBody: 'Corps du message', 25 emailBody: 'Corps du message',
26 emailSubject: 'Sujet du message', 26 emailSubject: 'Sujet du message',
diff --git a/sources/plugins/link/lang/gl.js b/sources/plugins/link/lang/gl.js
index 45ced42..a7d7b0b 100644
--- a/sources/plugins/link/lang/gl.js
+++ b/sources/plugins/link/lang/gl.js
@@ -19,8 +19,8 @@ CKEDITOR.plugins.setLang( 'link', 'gl', {
19 anchorName: 'Polo nome da ancoraxe', 19 anchorName: 'Polo nome da ancoraxe',
20 charset: 'Codificación do recurso ligado', 20 charset: 'Codificación do recurso ligado',
21 cssClasses: 'Clases da folla de estilos', 21 cssClasses: 'Clases da folla de estilos',
22 download: 'Force Download', // MISSING 22 download: 'Forzar a descarga',
23 displayText: 'Display Text', // MISSING 23 displayText: 'Amosar o texto',
24 emailAddress: 'Enderezo de correo', 24 emailAddress: 'Enderezo de correo',
25 emailBody: 'Corpo da mensaxe', 25 emailBody: 'Corpo da mensaxe',
26 emailSubject: 'Asunto da mensaxe', 26 emailSubject: 'Asunto da mensaxe',
diff --git a/sources/plugins/link/lang/hr.js b/sources/plugins/link/lang/hr.js
index 898b18b..5bb1b88 100644
--- a/sources/plugins/link/lang/hr.js
+++ b/sources/plugins/link/lang/hr.js
@@ -5,8 +5,8 @@ For licensing, see LICENSE.md or http://ckeditor.com/license
5CKEDITOR.plugins.setLang( 'link', 'hr', { 5CKEDITOR.plugins.setLang( 'link', 'hr', {
6 acccessKey: 'Pristupna tipka', 6 acccessKey: 'Pristupna tipka',
7 advanced: 'Napredno', 7 advanced: 'Napredno',
8 advisoryContentType: 'Advisory vrsta sadržaja', 8 advisoryContentType: 'Savjetodavna vrsta sadržaja',
9 advisoryTitle: 'Advisory naslov', 9 advisoryTitle: 'Savjetodavni naslov',
10 anchor: { 10 anchor: {
11 toolbar: 'Ubaci/promijeni sidro', 11 toolbar: 'Ubaci/promijeni sidro',
12 menu: 'Svojstva sidra', 12 menu: 'Svojstva sidra',
@@ -19,8 +19,8 @@ CKEDITOR.plugins.setLang( 'link', 'hr', {
19 anchorName: 'Po nazivu sidra', 19 anchorName: 'Po nazivu sidra',
20 charset: 'Kodna stranica povezanih resursa', 20 charset: 'Kodna stranica povezanih resursa',
21 cssClasses: 'Stylesheet klase', 21 cssClasses: 'Stylesheet klase',
22 download: 'Force Download', // MISSING 22 download: 'Preuzmi na silu',
23 displayText: 'Display Text', // MISSING 23 displayText: 'Prikaži tekst',
24 emailAddress: 'E-Mail adresa', 24 emailAddress: 'E-Mail adresa',
25 emailBody: 'Sadržaj poruke', 25 emailBody: 'Sadržaj poruke',
26 emailSubject: 'Naslov', 26 emailSubject: 'Naslov',
@@ -56,12 +56,12 @@ CKEDITOR.plugins.setLang( 'link', 'hr', {
56 targetFrameName: 'Ime ciljnog okvira', 56 targetFrameName: 'Ime ciljnog okvira',
57 targetPopup: '<popup prozor>', 57 targetPopup: '<popup prozor>',
58 targetPopupName: 'Naziv popup prozora', 58 targetPopupName: 'Naziv popup prozora',
59 title: 'Link', 59 title: 'Veza',
60 toAnchor: 'Sidro na ovoj stranici', 60 toAnchor: 'Sidro na ovoj stranici',
61 toEmail: 'E-Mail', 61 toEmail: 'E-Mail',
62 toUrl: 'URL', 62 toUrl: 'URL',
63 toolbar: 'Ubaci/promijeni link', 63 toolbar: 'Ubaci/promijeni vezu',
64 type: 'Link vrsta', 64 type: 'Vrsta veze',
65 unlink: 'Ukloni link', 65 unlink: 'Ukloni vezu',
66 upload: 'Pošalji' 66 upload: 'Pošalji'
67} ); 67} );
diff --git a/sources/plugins/link/lang/hu.js b/sources/plugins/link/lang/hu.js
index 52c09a8..102ca56 100644
--- a/sources/plugins/link/lang/hu.js
+++ b/sources/plugins/link/lang/hu.js
@@ -19,8 +19,8 @@ CKEDITOR.plugins.setLang( 'link', 'hu', {
19 anchorName: 'Horgony név szerint', 19 anchorName: 'Horgony név szerint',
20 charset: 'Hivatkozott tartalom kódlapja', 20 charset: 'Hivatkozott tartalom kódlapja',
21 cssClasses: 'Stíluskészlet', 21 cssClasses: 'Stíluskészlet',
22 download: 'Force Download', // MISSING 22 download: 'Kötelező letöltés',
23 displayText: 'Display Text', // MISSING 23 displayText: 'Megjeletett szöveg',
24 emailAddress: 'E-Mail cím', 24 emailAddress: 'E-Mail cím',
25 emailBody: 'Üzenet', 25 emailBody: 'Üzenet',
26 emailSubject: 'Üzenet tárgya', 26 emailSubject: 'Üzenet tárgya',
diff --git a/sources/plugins/link/lang/ja.js b/sources/plugins/link/lang/ja.js
index 94108b5..342025f 100644
--- a/sources/plugins/link/lang/ja.js
+++ b/sources/plugins/link/lang/ja.js
@@ -19,8 +19,8 @@ CKEDITOR.plugins.setLang( 'link', 'ja', {
19 anchorName: 'アンカー名', 19 anchorName: 'アンカー名',
20 charset: 'リンク先のcharset', 20 charset: 'リンク先のcharset',
21 cssClasses: 'スタイルシートクラス', 21 cssClasses: 'スタイルシートクラス',
22 download: 'Force Download', // MISSING 22 download: '強制的にダウンロード',
23 displayText: 'Display Text', // MISSING 23 displayText: '表示文字',
24 emailAddress: 'E-Mail アドレス', 24 emailAddress: 'E-Mail アドレス',
25 emailBody: '本文', 25 emailBody: '本文',
26 emailSubject: '件名', 26 emailSubject: '件名',
diff --git a/sources/plugins/link/lang/ko.js b/sources/plugins/link/lang/ko.js
index 86a797d..894ac62 100644
--- a/sources/plugins/link/lang/ko.js
+++ b/sources/plugins/link/lang/ko.js
@@ -19,8 +19,8 @@ CKEDITOR.plugins.setLang( 'link', 'ko', {
19 anchorName: '책갈피 이름', 19 anchorName: '책갈피 이름',
20 charset: '링크된 자료 문자열 인코딩', 20 charset: '링크된 자료 문자열 인코딩',
21 cssClasses: '스타일시트 클래스', 21 cssClasses: '스타일시트 클래스',
22 download: 'Force Download', // MISSING 22 download: '강제 다운로드',
23 displayText: 'Display Text', // MISSING 23 displayText: '보이는 글자',
24 emailAddress: '이메일 주소', 24 emailAddress: '이메일 주소',
25 emailBody: '메시지 내용', 25 emailBody: '메시지 내용',
26 emailSubject: '메시지 제목', 26 emailSubject: '메시지 제목',
diff --git a/sources/plugins/link/lang/ku.js b/sources/plugins/link/lang/ku.js
index 16faf24..ad06cd9 100644
--- a/sources/plugins/link/lang/ku.js
+++ b/sources/plugins/link/lang/ku.js
@@ -19,8 +19,8 @@ CKEDITOR.plugins.setLang( 'link', 'ku', {
19 anchorName: 'بەپێی ناوی لەنگەر', 19 anchorName: 'بەپێی ناوی لەنگەر',
20 charset: 'بەستەری سەرچاوەی نووسە', 20 charset: 'بەستەری سەرچاوەی نووسە',
21 cssClasses: 'شێوازی چینی پەڕه', 21 cssClasses: 'شێوازی چینی پەڕه',
22 download: 'Force Download', // MISSING 22 download: 'داگرتنی بەهێز',
23 displayText: 'Display Text', // MISSING 23 displayText: 'پیشاندانی دەق',
24 emailAddress: 'ناونیشانی ئیمەیل', 24 emailAddress: 'ناونیشانی ئیمەیل',
25 emailBody: 'ناوەڕۆکی نامە', 25 emailBody: 'ناوەڕۆکی نامە',
26 emailSubject: 'بابەتی نامە', 26 emailSubject: 'بابەتی نامە',
diff --git a/sources/plugins/link/lang/ru.js b/sources/plugins/link/lang/ru.js
index 7f4b775..7bc00d5 100644
--- a/sources/plugins/link/lang/ru.js
+++ b/sources/plugins/link/lang/ru.js
@@ -19,7 +19,7 @@ CKEDITOR.plugins.setLang( 'link', 'ru', {
19 anchorName: 'По имени', 19 anchorName: 'По имени',
20 charset: 'Кодировка ресурса', 20 charset: 'Кодировка ресурса',
21 cssClasses: 'Классы CSS', 21 cssClasses: 'Классы CSS',
22 download: 'Force Download', // MISSING 22 download: 'Скачать как файл',
23 displayText: 'Отображаемый текст', 23 displayText: 'Отображаемый текст',
24 emailAddress: 'Email адрес', 24 emailAddress: 'Email адрес',
25 emailBody: 'Текст сообщения', 25 emailBody: 'Текст сообщения',
diff --git a/sources/plugins/link/lang/sk.js b/sources/plugins/link/lang/sk.js
index 87b60bd..6383fc9 100644
--- a/sources/plugins/link/lang/sk.js
+++ b/sources/plugins/link/lang/sk.js
@@ -19,8 +19,8 @@ CKEDITOR.plugins.setLang( 'link', 'sk', {
19 anchorName: 'Podľa mena kotvy', 19 anchorName: 'Podľa mena kotvy',
20 charset: 'Priradená znaková sada', 20 charset: 'Priradená znaková sada',
21 cssClasses: 'Triedy štýlu', 21 cssClasses: 'Triedy štýlu',
22 download: 'Force Download', // MISSING 22 download: 'Vynútené sťahovanie.',
23 displayText: 'Display Text', // MISSING 23 displayText: 'Zobraziť text',
24 emailAddress: 'E-Mailová adresa', 24 emailAddress: 'E-Mailová adresa',
25 emailBody: 'Telo správy', 25 emailBody: 'Telo správy',
26 emailSubject: 'Predmet správy', 26 emailSubject: 'Predmet správy',
diff --git a/sources/plugins/link/lang/zh.js b/sources/plugins/link/lang/zh.js
index 5ba3d1c..a2cee62 100644
--- a/sources/plugins/link/lang/zh.js
+++ b/sources/plugins/link/lang/zh.js
@@ -19,7 +19,7 @@ CKEDITOR.plugins.setLang( 'link', 'zh', {
19 anchorName: '依錨點名稱', 19 anchorName: '依錨點名稱',
20 charset: '連結資源的字元集', 20 charset: '連結資源的字元集',
21 cssClasses: '樣式表類別', 21 cssClasses: '樣式表類別',
22 download: 'Force Download', // MISSING 22 download: '強制下載',
23 displayText: '顯示文字', 23 displayText: '顯示文字',
24 emailAddress: '電子郵件地址', 24 emailAddress: '電子郵件地址',
25 emailBody: '郵件本文', 25 emailBody: '郵件本文',
diff --git a/sources/plugins/link/plugin.js b/sources/plugins/link/plugin.js
index 94d582b..120097f 100644
--- a/sources/plugins/link/plugin.js
+++ b/sources/plugins/link/plugin.js
@@ -9,7 +9,7 @@
9 CKEDITOR.plugins.add( 'link', { 9 CKEDITOR.plugins.add( 'link', {
10 requires: 'dialog,fakeobjects', 10 requires: 'dialog,fakeobjects',
11 // jscs:disable maximumLineLength 11 // jscs:disable maximumLineLength
12 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE% 12 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,es-mx,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
13 // jscs:enable maximumLineLength 13 // jscs:enable maximumLineLength
14 icons: 'anchor,anchor-rtl,link,unlink', // %REMOVE_LINE_CORE% 14 icons: 'anchor,anchor-rtl,link,unlink', // %REMOVE_LINE_CORE%
15 hidpi: true, // %REMOVE_LINE_CORE% 15 hidpi: true, // %REMOVE_LINE_CORE%
@@ -92,9 +92,12 @@
92 CKEDITOR.dialog.add( 'anchor', this.path + 'dialogs/anchor.js' ); 92 CKEDITOR.dialog.add( 'anchor', this.path + 'dialogs/anchor.js' );
93 93
94 editor.on( 'doubleclick', function( evt ) { 94 editor.on( 'doubleclick', function( evt ) {
95 var element = CKEDITOR.plugins.link.getSelectedLink( editor ) || evt.data.element; 95 // If the link has descendants and the last part of it is also a part of a word partially
96 // unlinked, clicked element may be a descendant of the link, not the link itself (http://dev.ckeditor.com/ticket/11956).
97 // The evt.data.element.getAscendant( 'img', 1 ) condition allows opening anchor dialog if the anchor is empty (#501).
98 var element = evt.data.element.getAscendant( { a: 1, img: 1 }, true );
96 99
97 if ( !element.isReadOnly() ) { 100 if ( element && !element.isReadOnly() ) {
98 if ( element.is( 'a' ) ) { 101 if ( element.is( 'a' ) ) {
99 evt.data.dialog = ( element.getAttribute( 'name' ) && ( !element.getAttribute( 'href' ) || !element.getChildCount() ) ) ? 'anchor' : 'link'; 102 evt.data.dialog = ( element.getAttribute( 'name' ) && ( !element.getAttribute( 'href' ) || !element.getChildCount() ) ) ? 'anchor' : 'link';
100 103
@@ -108,7 +111,7 @@
108 111
109 // If event was cancelled, link passed in event data will not be selected. 112 // If event was cancelled, link passed in event data will not be selected.
110 editor.on( 'doubleclick', function( evt ) { 113 editor.on( 'doubleclick', function( evt ) {
111 // Make sure both links and anchors are selected (#11822). 114 // Make sure both links and anchors are selected (http://dev.ckeditor.com/ticket/11822).
112 if ( evt.data.dialog in { link: 1, anchor: 1 } && evt.data.link ) 115 if ( evt.data.dialog in { link: 1, anchor: 1 } && evt.data.link )
113 editor.getSelection().selectElement( evt.data.link ); 116 editor.getSelection().selectElement( evt.data.link );
114 }, null, null, 20 ); 117 }, null, null, 20 );
@@ -311,20 +314,38 @@
311 * 314 *
312 * @since 3.2.1 315 * @since 3.2.1
313 * @param {CKEDITOR.editor} editor 316 * @param {CKEDITOR.editor} editor
317 * @param {Boolean} [returnMultiple=false] Indicates whether the function should return only the first selected link or all of them.
318 * @returns {CKEDITOR.dom.element/CKEDITOR.dom.element[]/null} A single link element or an array of link
319 * elements relevant to the current selection.
314 */ 320 */
315 getSelectedLink: function( editor ) { 321 getSelectedLink: function( editor, returnMultiple ) {
316 var selection = editor.getSelection(); 322 var selection = editor.getSelection(),
317 var selectedElement = selection.getSelectedElement(); 323 selectedElement = selection.getSelectedElement(),
318 if ( selectedElement && selectedElement.is( 'a' ) ) 324 ranges = selection.getRanges(),
325 links = [],
326 link,
327 range,
328 i;
329
330 if ( !returnMultiple && selectedElement && selectedElement.is( 'a' ) ) {
319 return selectedElement; 331 return selectedElement;
332 }
333
334 for ( i = 0; i < ranges.length; i++ ) {
335 range = selection.getRanges()[ i ];
320 336
321 var range = selection.getRanges()[ 0 ]; 337 // Skip bogus to cover cases of multiple selection inside tables (#tp2245).
338 range.shrink( CKEDITOR.SHRINK_TEXT, false, { skipBogus: true } );
339 link = editor.elementPath( range.getCommonAncestor() ).contains( 'a', 1 );
322 340
323 if ( range ) { 341 if ( link && returnMultiple ) {
324 range.shrink( CKEDITOR.SHRINK_TEXT ); 342 links.push( link );
325 return editor.elementPath( range.getCommonAncestor() ).contains( 'a', 1 ); 343 } else if ( link ) {
344 return link;
345 }
326 } 346 }
327 return null; 347
348 return returnMultiple ? links : null;
328 }, 349 },
329 350
330 /** 351 /**
@@ -340,7 +361,7 @@
340 var editable = editor.editable(), 361 var editable = editor.editable(),
341 362
342 // The scope of search for anchors is the entire document for inline editors 363 // The scope of search for anchors is the entire document for inline editors
343 // and editor's editable for classic editor/divarea (#11359). 364 // and editor's editable for classic editor/divarea (http://dev.ckeditor.com/ticket/11359).
344 scope = ( editable.isInline() && !editor.plugins.divarea ) ? editor.document : editable, 365 scope = ( editable.isInline() && !editor.plugins.divarea ) ? editor.document : editable,
345 366
346 links = scope.getElementsByTag( 'a' ), 367 links = scope.getElementsByTag( 'a' ),
@@ -384,7 +405,7 @@
384 fakeAnchor: true, 405 fakeAnchor: true,
385 406
386 /** 407 /**
387 * For browsers that do not support CSS3 `a[name]:empty()`. Note that IE9 is included because of #7783. 408 * For browsers that do not support CSS3 `a[name]:empty()`. Note that IE9 is included because of http://dev.ckeditor.com/ticket/7783.
388 * 409 *
389 * @readonly 410 * @readonly
390 * @deprecated 4.3.3 It is set to `false` in every browser. 411 * @deprecated 4.3.3 It is set to `false` in every browser.
@@ -438,7 +459,7 @@
438 if ( ( javascriptMatch = href.match( javascriptProtocolRegex ) ) ) { 459 if ( ( javascriptMatch = href.match( javascriptProtocolRegex ) ) ) {
439 if ( emailProtection == 'encode' ) { 460 if ( emailProtection == 'encode' ) {
440 href = href.replace( encodedEmailLinkRegex, function( match, protectedAddress, rest ) { 461 href = href.replace( encodedEmailLinkRegex, function( match, protectedAddress, rest ) {
441 // Without it 'undefined' is appended to e-mails without subject and body (#9192). 462 // Without it 'undefined' is appended to e-mails without subject and body (http://dev.ckeditor.com/ticket/9192).
442 rest = rest || ''; 463 rest = rest || '';
443 464
444 return 'mailto:' + 465 return 'mailto:' +
@@ -513,7 +534,7 @@
513 534
514 var featureMatch; 535 var featureMatch;
515 while ( ( featureMatch = popupFeaturesRegex.exec( onclickMatch[ 2 ] ) ) ) { 536 while ( ( featureMatch = popupFeaturesRegex.exec( onclickMatch[ 2 ] ) ) ) {
516 // Some values should remain numbers (#7300) 537 // Some values should remain numbers (http://dev.ckeditor.com/ticket/7300)
517 if ( ( featureMatch[ 2 ] == 'yes' || featureMatch[ 2 ] == '1' ) && !( featureMatch[ 1 ] in { height: 1, width: 1, top: 1, left: 1 } ) ) 538 if ( ( featureMatch[ 2 ] == 'yes' || featureMatch[ 2 ] == '1' ) && !( featureMatch[ 1 ] in { height: 1, width: 1, top: 1, left: 1 } ) )
518 retval.target[ featureMatch[ 1 ] ] = true; 539 retval.target[ featureMatch[ 1 ] ] = true;
519 else if ( isFinite( featureMatch[ 2 ] ) ) 540 else if ( isFinite( featureMatch[ 2 ] ) )
@@ -689,7 +710,7 @@
689 set[ 'data-cke-saved-name' ] = set.name; 710 set[ 'data-cke-saved-name' ] = set.name;
690 } 711 }
691 712
692 // Browser need the "href" fro copy/paste link to work. (#6641) 713 // Browser need the "href" fro copy/paste link to work. (http://dev.ckeditor.com/ticket/6641)
693 if ( set[ 'data-cke-saved-href' ] ) 714 if ( set[ 'data-cke-saved-href' ] )
694 set.href = set[ 'data-cke-saved-href' ]; 715 set.href = set[ 'data-cke-saved-href' ];
695 716
@@ -726,21 +747,26 @@
726 */ 747 */
727 showDisplayTextForElement: function( element, editor ) { 748 showDisplayTextForElement: function( element, editor ) {
728 var undesiredElements = { 749 var undesiredElements = {
729 img: 1, 750 img: 1,
730 table: 1, 751 table: 1,
731 tbody: 1, 752 tbody: 1,
732 thead: 1, 753 thead: 1,
733 tfoot: 1, 754 tfoot: 1,
734 input: 1, 755 input: 1,
735 select: 1, 756 select: 1,
736 textarea: 1 757 textarea: 1
737 }; 758 },
759 selection = editor.getSelection();
738 760
739 // Widget duck typing, we don't want to show display text for widgets. 761 // Widget duck typing, we don't want to show display text for widgets.
740 if ( editor.widgets && editor.widgets.focused ) { 762 if ( editor.widgets && editor.widgets.focused ) {
741 return false; 763 return false;
742 } 764 }
743 765
766 if ( selection && selection.getRanges().length > 1 ) {
767 return false;
768 }
769
744 return !element || !element.getName || !element.is( undesiredElements ); 770 return !element || !element.getName || !element.is( undesiredElements );
745 } 771 }
746 }; 772 };
@@ -750,8 +776,29 @@
750 CKEDITOR.unlinkCommand = function() {}; 776 CKEDITOR.unlinkCommand = function() {};
751 CKEDITOR.unlinkCommand.prototype = { 777 CKEDITOR.unlinkCommand.prototype = {
752 exec: function( editor ) { 778 exec: function( editor ) {
779 // IE/Edge removes link from selection while executing "unlink" command when cursor
780 // is right before/after link's text. Therefore whole link must be selected and the
781 // position of cursor must be restored to its initial state after unlinking. (http://dev.ckeditor.com/ticket/13062)
782 if ( CKEDITOR.env.ie ) {
783 var range = editor.getSelection().getRanges()[ 0 ],
784 link = ( range.getPreviousEditableNode() && range.getPreviousEditableNode().getAscendant( 'a', true ) ) ||
785 ( range.getNextEditableNode() && range.getNextEditableNode().getAscendant( 'a', true ) ),
786 bookmark;
787
788 if ( range.collapsed && link ) {
789 bookmark = range.createBookmark();
790 range.selectNodeContents( link );
791 range.select();
792 }
793 }
794
753 var style = new CKEDITOR.style( { element: 'a', type: CKEDITOR.STYLE_INLINE, alwaysRemoveElement: 1 } ); 795 var style = new CKEDITOR.style( { element: 'a', type: CKEDITOR.STYLE_INLINE, alwaysRemoveElement: 1 } );
754 editor.removeStyle( style ); 796 editor.removeStyle( style );
797
798 if ( bookmark ) {
799 range.moveToBookmark( bookmark );
800 range.select();
801 }
755 }, 802 },
756 803
757 refresh: function( editor, path ) { 804 refresh: function( editor, path ) {
@@ -768,7 +815,8 @@
768 815
769 contextSensitive: 1, 816 contextSensitive: 1,
770 startDisabled: 1, 817 startDisabled: 1,
771 requiredContent: 'a[href]' 818 requiredContent: 'a[href]',
819 editorFocus: 1
772 }; 820 };
773 821
774 CKEDITOR.removeAnchorCommand = function() {}; 822 CKEDITOR.removeAnchorCommand = function() {};