Skip to content

Commit 1f1a9b3

Browse files
committed
Merge branch 't/13516b'
2 parents 623ade3 + e554ff7 commit 1f1a9b3

File tree

6 files changed

+85
-12
lines changed

6 files changed

+85
-12
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Fixed Issues:
2020
* [#11724](http://dev.ckeditor.com/ticket/11724): [Touch devices] Fixed: Drop-downs often hide right after opening them.
2121
* [#13690](http://dev.ckeditor.com/ticket/13690): Fixed: Copying content from IE to Chrome adding extra paragraph.
2222
* [#13284](http://dev.ckeditor.com/ticket/13284): Fixed: Cannot drag and drop a widget if a text caret is placed just after widget instance.
23+
* [#13516](http://dev.ckeditor.com/ticket/13516): Fixed: CKEditor removes empty html5 anchors without name attribute.
2324

2425
Other Changes:
2526

core/filter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1689,7 +1689,7 @@
16891689
switch ( element.name ) {
16901690
case 'a':
16911691
// Code borrowed from htmlDataProcessor, so ACF does the same clean up.
1692-
if ( !( element.children.length || element.attributes.name ) )
1692+
if ( !( element.children.length || element.attributes.name || element.attributes.id ) )
16931693
return false;
16941694
break;
16951695
case 'img':

core/htmldataprocessor.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,9 +602,11 @@
602602
}
603603
},
604604

605-
// Remove empty link but not empty anchor. (#3829)
605+
// Remove empty link but not empty anchor. (#3829, #13516)
606606
a: function( element ) {
607-
if ( !( element.children.length || element.attributes.name || element.attributes[ 'data-cke-saved-name' ] ) )
607+
var attrs = element.attributes;
608+
609+
if ( !( element.children.length || attrs.name || attrs.id || element.attributes[ 'data-cke-saved-name' ] ) )
608610
return false;
609611
}
610612
}

tests/core/filter/filter.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,11 +619,18 @@
619619
filter( '<p>X<a name="x">A</a>X</p>', '<p>X<a name="x">A</a>X</p>' );
620620
filter( '<p>X<a name="x"><img src="x" /></a>X</p>', '<p>X<a name="x"></a>X</p>' );
621621
filter( '<p>X<a href="x" name="x">A</a>X</p>', '<p>X<a name="x">A</a>X</p>' );
622-
// Empty <a> element isn't correct unless it is an anchor (has non-empty name attrbiute).
622+
// Empty <a> element isn't correct unless it is an anchor (has non-empty name or id attrbiute).
623623
// This behaviour conforms to the htmlDP's htmlFilter.
624624
filter( '<p>X<a href="x" name=""></a>X</p>', '<p>XX</p>' );
625625
filter( '<p>X<a name="x" href="x"><img /></a>X</p>', '<p>X<a name="x"></a>X</p>' );
626626

627+
filter = createFilter( 'p; a[!id]' );
628+
filter( '<p>X<a name="x"></a>X</p>', '<p>XX</p>' );
629+
filter( '<p>X<a id=""></a>X</p>', '<p>XX</p>' );
630+
filter( '<p>X<a id="x"></a>X</p>', '<p>X<a id="x"></a>X</p>' );
631+
filter( '<p>X<a id="x" name="x"></a>X</p>', '<p>X<a id="x"></a>X</p>' );
632+
filter( '<p>X<a id="x" name="x">foo</a>X</p>', '<p>X<a id="x">foo</a>X</p>' );
633+
627634
filter = createFilter( 'p; a[!href]' );
628635

629636
filter( '<p>X<a href="">A</a>X</p>', '<p>X<a href="">A</a>X</p>' );

tests/core/htmldataprocessor.js

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
setUp: function() {
125125
// Force result data un-formatted.
126126
this.editor.dataProcessor.writer._.rules = {};
127+
this.editor.dataProcessor.writer.sortAttributes = true;
127128
this.editor.focus();
128129
},
129130

@@ -391,19 +392,49 @@
391392
assert.areSame( html , dataProcessor.toDataFormat( protectedHtml ) );
392393
},
393394

394-
/**
395-
* Test empty value attributes.
396-
*/
397-
test_ticket_3884: function() {
398-
var editor = this.editor,
399-
dataProcessor = editor.dataProcessor;
400-
dataProcessor.writer = new CKEDITOR.htmlParser.basicWriter();
401-
dataProcessor.writer.sortAttributes = true;
395+
'test link with empty href': function() {
396+
var dataProcessor = this.editor.dataProcessor;
402397

403398
assert.areSame( '<p><a href="" name="">emptylink</a></p>',
404399
dataProcessor.toDataFormat( dataProcessor.toHtml( '<p><a href="" name="">emptylink</a></p>' ) ) );
405400
},
406401

402+
'test empty link': function() {
403+
var dataProcessor = this.editor.dataProcessor;
404+
405+
assert.areSame( '<p>xx</p>', dataProcessor.toDataFormat( '<p>x<a href="foo"></a>x</p>' ), 'toDF' );
406+
407+
assert.areSame( '<p>xx</p>', dataProcessor.toHtml( '<p>x<a href="foo"></a>x</p>' ), 'toHtml' );
408+
},
409+
410+
'test empty anchor with name': function() {
411+
var dataProcessor = this.editor.dataProcessor;
412+
413+
assert.areSame( '<p>x<a name="foo"></a>x</p>',
414+
dataProcessor.toDataFormat( '<p>x<a data-cke-saved-name="foo" name="foo"></a>x</p>' ), 'toDF' );
415+
416+
assert.areSame( '<p>x<a data-cke-saved-name="foo" name="foo"></a>x</p>',
417+
dataProcessor.toHtml( '<p>x<a name="foo"></a>x</p>' ), 'toHtml' );
418+
},
419+
420+
'test empty anchor with id': function() {
421+
var dataProcessor = this.editor.dataProcessor;
422+
423+
assert.areSame( '<p>x<a id="foo"></a>x</p>', dataProcessor.toDataFormat( '<p>x<a id="foo"></a>x</p>' ), 'toDF' );
424+
425+
assert.areSame( '<p>x<a id="foo"></a>x</p>', dataProcessor.toHtml( '<p>x<a id="foo"></a>x</p>' ), 'toHtml' );
426+
},
427+
428+
'test empty anchor with name and id': function() {
429+
var dataProcessor = this.editor.dataProcessor;
430+
431+
assert.areSame( '<p>x<a id="bar" name="foo"></a>x</p>',
432+
dataProcessor.toDataFormat( '<p>x<a data-cke-saved-name="foo" id="bar" name="foo"></a>x</p>' ), 'toDF' );
433+
434+
assert.areSame( '<p>x<a data-cke-saved-name="foo" id="bar" name="foo"></a>x</p>',
435+
bender.tools.fixHtml( dataProcessor.toHtml( '<p>x<a id="bar" name="foo"></a>x</p>' ) ), 'toHtml' );
436+
},
437+
407438
test_innerHtmlComments_ticket_3801: function() {
408439
var editor = this.editor,
409440
dataProcessor = editor.dataProcessor;

tests/core/htmlparser/htmlparser.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,38 @@
316316
'test header elements in summary tag': function() {
317317
assert.areSame( '<summary><h2>Summary</h2></summary>',
318318
htmlParse( '<summary><h2>Summary</h2></summary>' ) );
319+
},
320+
321+
'test link': function() {
322+
assert.areSame( '<a href="foo">bar</a>', htmlParse( '<a href="foo">bar</a>' ) );
323+
},
324+
325+
'test empty link': function() {
326+
assert.areSame( '', htmlParse( '<a href="foo"></a>' ) );
327+
},
328+
329+
'test anchor with name': function() {
330+
assert.areSame( '<a name="foo">bar</a>', htmlParse( '<a name="foo">bar</a>' ) );
331+
},
332+
333+
'test anchor with id': function() {
334+
assert.areSame( '<a id="foo">bar</a>', htmlParse( '<a id="foo">bar</a>' ) );
335+
},
336+
337+
'test anchor with name and id': function() {
338+
assert.areSame( '<a id="foo" name="bom">bar</a>', htmlParse( '<a id="foo" name="bom">bar</a>' ) );
339+
},
340+
341+
'test empty anchor with name': function() {
342+
assert.areSame( '<a name="foo"></a>', htmlParse( '<a name="foo"></a>' ) );
343+
},
344+
345+
'test empty anchor with id': function() {
346+
assert.areSame( '<a id="foo"></a>', htmlParse( '<a id="foo"></a>' ) );
347+
},
348+
349+
'test empty anchor with name and id': function() {
350+
assert.areSame( '<a id="foo" name="bom"></a>', htmlParse( '<a id="foo" name="bom"></a>' ) );
319351
}
320352
} );
321353

0 commit comments

Comments
 (0)