diff options
Diffstat (limited to 'sources/core/htmldataprocessor.js')
-rw-r--r-- | sources/core/htmldataprocessor.js | 77 |
1 files changed, 47 insertions, 30 deletions
diff --git a/sources/core/htmldataprocessor.js b/sources/core/htmldataprocessor.js index d079e4d..79e996b 100644 --- a/sources/core/htmldataprocessor.js +++ b/sources/core/htmldataprocessor.js | |||
@@ -1,5 +1,5 @@ | |||
1 | /** | 1 | /** |
2 | * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. | 2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. |
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | 3 | * For licensing, see LICENSE.md or http://ckeditor.com/license |
4 | */ | 4 | */ |
5 | 5 | ||
@@ -56,7 +56,7 @@ | |||
56 | // it up and apply the filter. | 56 | // it up and apply the filter. |
57 | data = protectSource( data, editor ); | 57 | data = protectSource( data, editor ); |
58 | 58 | ||
59 | // Protect content of textareas. (#9995) | 59 | // Protect content of textareas. (http://dev.ckeditor.com/ticket/9995) |
60 | // Do this before protecting attributes to avoid breaking: | 60 | // Do this before protecting attributes to avoid breaking: |
61 | // <textarea><img src="..." /></textarea> | 61 | // <textarea><img src="..." /></textarea> |
62 | data = protectElements( data, protectTextareaRegex ); | 62 | data = protectElements( data, protectTextareaRegex ); |
@@ -67,23 +67,23 @@ | |||
67 | data = protectAttributes( data ); | 67 | data = protectAttributes( data ); |
68 | 68 | ||
69 | // Protect elements than can't be set inside a DIV. E.g. IE removes | 69 | // Protect elements than can't be set inside a DIV. E.g. IE removes |
70 | // style tags from innerHTML. (#3710) | 70 | // style tags from innerHTML. (http://dev.ckeditor.com/ticket/3710) |
71 | data = protectElements( data, protectElementsRegex ); | 71 | data = protectElements( data, protectElementsRegex ); |
72 | 72 | ||
73 | // Certain elements has problem to go through DOM operation, protect | 73 | // Certain elements has problem to go through DOM operation, protect |
74 | // them by prefixing 'cke' namespace. (#3591) | 74 | // them by prefixing 'cke' namespace. (http://dev.ckeditor.com/ticket/3591) |
75 | data = protectElementsNames( data ); | 75 | data = protectElementsNames( data ); |
76 | 76 | ||
77 | // All none-IE browsers ignore self-closed custom elements, | 77 | // All none-IE browsers ignore self-closed custom elements, |
78 | // protecting them into open-close. (#3591) | 78 | // protecting them into open-close. (http://dev.ckeditor.com/ticket/3591) |
79 | data = protectSelfClosingElements( data ); | 79 | data = protectSelfClosingElements( data ); |
80 | 80 | ||
81 | // Compensate one leading line break after <pre> open as browsers | 81 | // Compensate one leading line break after <pre> open as browsers |
82 | // eat it up. (#5789) | 82 | // eat it up. (http://dev.ckeditor.com/ticket/5789) |
83 | data = protectPreFormatted( data ); | 83 | data = protectPreFormatted( data ); |
84 | 84 | ||
85 | // There are attributes which may execute JavaScript code inside fixBin. | 85 | // There are attributes which may execute JavaScript code inside fixBin. |
86 | // Encode them greedily. They will be unprotected right after getting HTML from fixBin. (#10) | 86 | // Encode them greedily. They will be unprotected right after getting HTML from fixBin. (http://dev.ckeditor.com/ticket/10) |
87 | data = protectInsecureAttributes( data ); | 87 | data = protectInsecureAttributes( data ); |
88 | 88 | ||
89 | var fixBin = evtData.context || editor.editable().getName(), | 89 | var fixBin = evtData.context || editor.editable().getName(), |
@@ -99,7 +99,7 @@ | |||
99 | // Call the browser to help us fixing a possibly invalid HTML | 99 | // Call the browser to help us fixing a possibly invalid HTML |
100 | // structure. | 100 | // structure. |
101 | var el = editor.document.createElement( fixBin ); | 101 | var el = editor.document.createElement( fixBin ); |
102 | // Add fake character to workaround IE comments bug. (#3801) | 102 | // Add fake character to workaround IE comments bug. (http://dev.ckeditor.com/ticket/3801) |
103 | el.setHtml( 'a' + data ); | 103 | el.setHtml( 'a' + data ); |
104 | data = el.getHtml().substr( 1 ); | 104 | data = el.getHtml().substr( 1 ); |
105 | 105 | ||
@@ -128,7 +128,7 @@ | |||
128 | data = CKEDITOR.htmlParser.fragment.fromHtml( data, evtData.context, fixBodyTag ); | 128 | data = CKEDITOR.htmlParser.fragment.fromHtml( data, evtData.context, fixBodyTag ); |
129 | 129 | ||
130 | // The empty root element needs to be fixed by adding 'p' or 'div' into it. | 130 | // The empty root element needs to be fixed by adding 'p' or 'div' into it. |
131 | // This avoids the need to create that element on the first focus (#12630). | 131 | // This avoids the need to create that element on the first focus (http://dev.ckeditor.com/ticket/12630). |
132 | if ( fixBodyTag ) { | 132 | if ( fixBodyTag ) { |
133 | fixEmptyRoot( data, fixBodyTag ); | 133 | fixEmptyRoot( data, fixBodyTag ); |
134 | } | 134 | } |
@@ -163,7 +163,7 @@ | |||
163 | editor.on( 'toDataFormat', function( evt ) { | 163 | editor.on( 'toDataFormat', function( evt ) { |
164 | var data = evt.data.dataValue; | 164 | var data = evt.data.dataValue; |
165 | 165 | ||
166 | // #10854 - we need to strip leading blockless <br> which FF adds | 166 | // http://dev.ckeditor.com/ticket/10854 - we need to strip leading blockless <br> which FF adds |
167 | // automatically when editable contains only non-editable content. | 167 | // automatically when editable contains only non-editable content. |
168 | // We do that for every browser (so it's a constant behavior) and | 168 | // We do that for every browser (so it's a constant behavior) and |
169 | // not in BR mode, in which chance of valid leading blockless <br> is higher. | 169 | // not in BR mode, in which chance of valid leading blockless <br> is higher. |
@@ -192,7 +192,7 @@ | |||
192 | data.writeChildrenHtml( writer ); | 192 | data.writeChildrenHtml( writer ); |
193 | data = writer.getHtml( true ); | 193 | data = writer.getHtml( true ); |
194 | 194 | ||
195 | // Restore those non-HTML protected source. (#4475,#4880) | 195 | // Restore those non-HTML protected source. (http://dev.ckeditor.com/ticket/4475,http://dev.ckeditor.com/ticket/4880) |
196 | data = unprotectRealComments( data ); | 196 | data = unprotectRealComments( data ); |
197 | data = unprotectSource( data, editor ); | 197 | data = unprotectSource( data, editor ); |
198 | 198 | ||
@@ -448,7 +448,7 @@ | |||
448 | return false; | 448 | return false; |
449 | 449 | ||
450 | // 1. For IE version >=8, empty blocks are displayed correctly themself in wysiwiyg; | 450 | // 1. For IE version >=8, empty blocks are displayed correctly themself in wysiwiyg; |
451 | // 2. For the rest, at least table cell and list item need no filler space. (#6248) | 451 | // 2. For the rest, at least table cell and list item need no filler space. (http://dev.ckeditor.com/ticket/6248) |
452 | if ( !isOutput && !CKEDITOR.env.needsBrFiller && | 452 | if ( !isOutput && !CKEDITOR.env.needsBrFiller && |
453 | ( document.documentMode > 7 || | 453 | ( document.documentMode > 7 || |
454 | block.name in CKEDITOR.dtd.tr || | 454 | block.name in CKEDITOR.dtd.tr || |
@@ -484,7 +484,7 @@ | |||
484 | } | 484 | } |
485 | 485 | ||
486 | // Regex to scan for at the end of blocks, which are actually placeholders. | 486 | // Regex to scan for at the end of blocks, which are actually placeholders. |
487 | // Safari transforms the to \xa0. (#4172) | 487 | // Safari transforms the to \xa0. (http://dev.ckeditor.com/ticket/4172) |
488 | var tailNbspRegex = /(?: |\xa0)$/; | 488 | var tailNbspRegex = /(?: |\xa0)$/; |
489 | 489 | ||
490 | var protectedSourceMarker = '{cke_protected}'; | 490 | var protectedSourceMarker = '{cke_protected}'; |
@@ -563,18 +563,35 @@ | |||
563 | // active in the editing area (IE|WebKit). | 563 | // active in the editing area (IE|WebKit). |
564 | [ ( /^on/ ), 'data-cke-pa-on' ], | 564 | [ ( /^on/ ), 'data-cke-pa-on' ], |
565 | 565 | ||
566 | // Prevent iframe's srcdoc attribute from being evaluated in the editable. | ||
567 | [ ( /^srcdoc/ ), 'data-cke-pa-srcdoc' ], | ||
568 | |||
566 | // Don't let some old expando enter editor. Concerns only IE8, | 569 | // Don't let some old expando enter editor. Concerns only IE8, |
567 | // but for consistency remove on all browsers. | 570 | // but for consistency remove on all browsers. |
568 | [ ( /^data-cke-expando$/ ), '' ] | 571 | [ ( /^data-cke-expando$/ ), '' ] |
569 | ] | 572 | ], |
573 | |||
574 | elements: { | ||
575 | // Prevent iframe's src attribute with javascript code or data protocol from being evaluated in the editable. | ||
576 | iframe: function( element ) { | ||
577 | if ( element.attributes && element.attributes.src ) { | ||
578 | |||
579 | var src = element.attributes.src.toLowerCase().replace( /[^a-z]/gi, '' ); | ||
580 | if ( src.indexOf( 'javascript' ) === 0 || src.indexOf( 'data' ) === 0 ) { | ||
581 | element.attributes[ 'data-cke-pa-src' ] = element.attributes.src; | ||
582 | delete element.attributes.src; | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | } | ||
570 | }; | 587 | }; |
571 | 588 | ||
572 | // Disable form elements editing mode provided by some browsers. (#5746) | 589 | // Disable form elements editing mode provided by some browsers. (http://dev.ckeditor.com/ticket/5746) |
573 | function protectReadOnly( element ) { | 590 | function protectReadOnly( element ) { |
574 | var attrs = element.attributes; | 591 | var attrs = element.attributes; |
575 | 592 | ||
576 | // We should flag that the element was locked by our code so | 593 | // We should flag that the element was locked by our code so |
577 | // it'll be editable by the editor functions (#6046). | 594 | // it'll be editable by the editor functions (http://dev.ckeditor.com/ticket/6046). |
578 | if ( attrs.contenteditable != 'false' ) | 595 | if ( attrs.contenteditable != 'false' ) |
579 | attrs[ 'data-cke-editable' ] = attrs.contenteditable ? 'true' : 1; | 596 | attrs[ 'data-cke-editable' ] = attrs.contenteditable ? 'true' : 1; |
580 | 597 | ||
@@ -602,7 +619,7 @@ | |||
602 | } | 619 | } |
603 | }, | 620 | }, |
604 | 621 | ||
605 | // Remove empty link but not empty anchor. (#3829, #13516) | 622 | // Remove empty link but not empty anchor. (http://dev.ckeditor.com/ticket/3829, http://dev.ckeditor.com/ticket/13516) |
606 | a: function( element ) { | 623 | a: function( element ) { |
607 | var attrs = element.attributes; | 624 | var attrs = element.attributes; |
608 | 625 | ||
@@ -641,7 +658,7 @@ | |||
641 | if ( attribs[ 'data-cke-temp' ] ) | 658 | if ( attribs[ 'data-cke-temp' ] ) |
642 | return false; | 659 | return false; |
643 | 660 | ||
644 | // Remove duplicated attributes - #3789. | 661 | // Remove duplicated attributes - http://dev.ckeditor.com/ticket/3789. |
645 | var attributeNames = [ 'name', 'href', 'src' ], | 662 | var attributeNames = [ 'name', 'href', 'src' ], |
646 | savedAttributeName; | 663 | savedAttributeName; |
647 | for ( var i = 0; i < attributeNames.length; i++ ) { | 664 | for ( var i = 0; i < attributeNames.length; i++ ) { |
@@ -653,7 +670,7 @@ | |||
653 | return element; | 670 | return element; |
654 | }, | 671 | }, |
655 | 672 | ||
656 | // The contents of table should be in correct order (#4809). | 673 | // The contents of table should be in correct order (http://dev.ckeditor.com/ticket/4809). |
657 | table: function( element ) { | 674 | table: function( element ) { |
658 | // Clone the array as it would become empty during the sort call. | 675 | // Clone the array as it would become empty during the sort call. |
659 | var children = element.children.slice( 0 ); | 676 | var children = element.children.slice( 0 ); |
@@ -712,7 +729,7 @@ | |||
712 | title: function( element ) { | 729 | title: function( element ) { |
713 | var titleText = element.children[ 0 ]; | 730 | var titleText = element.children[ 0 ]; |
714 | 731 | ||
715 | // Append text-node to title tag if not present (i.e. non-IEs) (#9882). | 732 | // Append text-node to title tag if not present (i.e. non-IEs) (http://dev.ckeditor.com/ticket/9882). |
716 | !titleText && append( element, titleText = new CKEDITOR.htmlParser.text() ); | 733 | !titleText && append( element, titleText = new CKEDITOR.htmlParser.text() ); |
717 | 734 | ||
718 | // Transfer data-saved title to title tag. | 735 | // Transfer data-saved title to title tag. |
@@ -733,7 +750,7 @@ | |||
733 | 750 | ||
734 | if ( CKEDITOR.env.ie ) { | 751 | if ( CKEDITOR.env.ie ) { |
735 | // IE outputs style attribute in capital letters. We should convert | 752 | // IE outputs style attribute in capital letters. We should convert |
736 | // them back to lower case, while not hurting the values (#5930) | 753 | // them back to lower case, while not hurting the values (http://dev.ckeditor.com/ticket/5930) |
737 | defaultHtmlFilterRulesForAll.attributes.style = function( value ) { | 754 | defaultHtmlFilterRulesForAll.attributes.style = function( value ) { |
738 | return value.replace( /(^|;)([^\:]+)/g, function( match ) { | 755 | return value.replace( /(^|;)([^\:]+)/g, function( match ) { |
739 | return match.toLowerCase(); | 756 | return match.toLowerCase(); |
@@ -741,7 +758,7 @@ | |||
741 | }; | 758 | }; |
742 | } | 759 | } |
743 | 760 | ||
744 | // Disable form elements editing mode provided by some browsers. (#5746) | 761 | // Disable form elements editing mode provided by some browsers. (http://dev.ckeditor.com/ticket/5746) |
745 | function unprotectReadyOnly( element ) { | 762 | function unprotectReadyOnly( element ) { |
746 | var attrs = element.attributes; | 763 | var attrs = element.attributes; |
747 | switch ( attrs[ 'data-cke-editable' ] ) { | 764 | switch ( attrs[ 'data-cke-editable' ] ) { |
@@ -773,7 +790,7 @@ | |||
773 | // | 790 | // |
774 | // 'data-x' => '<a href="X"' | 791 | // 'data-x' => '<a href="X"' |
775 | // | 792 | // |
776 | // which, can be easily filtered out (#11508). | 793 | // which, can be easily filtered out (http://dev.ckeditor.com/ticket/11508). |
777 | protectAttributeRegex = /([\w-:]+)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+))/gi, | 794 | protectAttributeRegex = /([\w-:]+)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+))/gi, |
778 | protectAttributeNameRegex = /^(href|src|name)$/i; | 795 | protectAttributeNameRegex = /^(href|src|name)$/i; |
779 | 796 | ||
@@ -790,8 +807,8 @@ | |||
790 | function protectAttributes( html ) { | 807 | function protectAttributes( html ) { |
791 | return html.replace( protectElementRegex, function( element, tag, attributes ) { | 808 | return html.replace( protectElementRegex, function( element, tag, attributes ) { |
792 | return '<' + tag + attributes.replace( protectAttributeRegex, function( fullAttr, attrName ) { | 809 | return '<' + tag + attributes.replace( protectAttributeRegex, function( fullAttr, attrName ) { |
793 | // Avoid corrupting the inline event attributes (#7243). | 810 | // Avoid corrupting the inline event attributes (http://dev.ckeditor.com/ticket/7243). |
794 | // We should not rewrite the existed protected attributes, e.g. clipboard content from editor. (#5218) | 811 | // We should not rewrite the existed protected attributes, e.g. clipboard content from editor. (http://dev.ckeditor.com/ticket/5218) |
795 | if ( protectAttributeNameRegex.test( attrName ) && attributes.indexOf( 'data-cke-saved-' + attrName ) == -1 ) | 812 | if ( protectAttributeNameRegex.test( attrName ) && attributes.indexOf( 'data-cke-saved-' + attrName ) == -1 ) |
796 | return ' data-cke-saved-' + fullAttr + ' data-cke-' + CKEDITOR.rnd + '-' + fullAttr; | 813 | return ' data-cke-saved-' + fullAttr + ' data-cke-' + CKEDITOR.rnd + '-' + fullAttr; |
797 | 814 | ||
@@ -880,7 +897,7 @@ | |||
880 | // <noscript> tags (get lost in IE and messed up in FF). | 897 | // <noscript> tags (get lost in IE and messed up in FF). |
881 | /<noscript[\s\S]*?<\/noscript>/gi, | 898 | /<noscript[\s\S]*?<\/noscript>/gi, |
882 | 899 | ||
883 | // Avoid meta tags being stripped (#8117). | 900 | // Avoid meta tags being stripped (http://dev.ckeditor.com/ticket/8117). |
884 | /<meta[\s\S]*?\/?>/gi | 901 | /<meta[\s\S]*?\/?>/gi |
885 | ].concat( protectRegexes ); | 902 | ].concat( protectRegexes ); |
886 | 903 | ||
@@ -894,7 +911,7 @@ | |||
894 | 911 | ||
895 | for ( var i = 0; i < regexes.length; i++ ) { | 912 | for ( var i = 0; i < regexes.length; i++ ) { |
896 | data = data.replace( regexes[ i ], function( match ) { | 913 | data = data.replace( regexes[ i ], function( match ) { |
897 | match = match.replace( tempRegex, // There could be protected source inside another one. (#3869). | 914 | match = match.replace( tempRegex, // There could be protected source inside another one. (http://dev.ckeditor.com/ticket/3869). |
898 | function( $, isComment, id ) { | 915 | function( $, isComment, id ) { |
899 | return protectedHtml[ id ]; | 916 | return protectedHtml[ id ]; |
900 | } ); | 917 | } ); |
@@ -912,7 +929,7 @@ | |||
912 | 929 | ||
913 | // Different protection pattern is used for those that | 930 | // Different protection pattern is used for those that |
914 | // live in attributes to avoid from being HTML encoded. | 931 | // live in attributes to avoid from being HTML encoded. |
915 | // Why so serious? See #9205, #8216, #7805, #11754, #11846. | 932 | // Why so serious? See http://dev.ckeditor.com/ticket/9205, http://dev.ckeditor.com/ticket/8216, http://dev.ckeditor.com/ticket/7805, http://dev.ckeditor.com/ticket/11754, http://dev.ckeditor.com/ticket/11846. |
916 | data = data.replace( /<\w+(?:\s+(?:(?:[^\s=>]+\s*=\s*(?:[^'"\s>]+|'[^']*'|"[^"]*"))|[^\s=\/>]+))+\s*\/?>/g, function( match ) { | 933 | data = data.replace( /<\w+(?:\s+(?:(?:[^\s=>]+\s*=\s*(?:[^'"\s>]+|'[^']*'|"[^"]*"))|[^\s=\/>]+))+\s*\/?>/g, function( match ) { |
917 | return match.replace( /<!--\{cke_protected\}([^>]*)-->/g, function( match, data ) { | 934 | return match.replace( /<!--\{cke_protected\}([^>]*)-->/g, function( match, data ) { |
918 | store[ store.id ] = decodeURIComponent( data ); | 935 | store[ store.id ] = decodeURIComponent( data ); |
@@ -922,7 +939,7 @@ | |||
922 | 939 | ||
923 | // This RegExp searches for innerText in all the title/iframe/textarea elements. | 940 | // This RegExp searches for innerText in all the title/iframe/textarea elements. |
924 | // This is because browser doesn't allow HTML in these elements, that's why we can't | 941 | // This is because browser doesn't allow HTML in these elements, that's why we can't |
925 | // nest comments in there. (#11223) | 942 | // nest comments in there. (http://dev.ckeditor.com/ticket/11223) |
926 | data = data.replace( /<(title|iframe|textarea)([^>]*)>([\s\S]*?)<\/\1>/g, function( match, tagName, tagAttributes, innerText ) { | 943 | data = data.replace( /<(title|iframe|textarea)([^>]*)>([\s\S]*?)<\/\1>/g, function( match, tagName, tagAttributes, innerText ) { |
927 | return '<' + tagName + tagAttributes + '>' + unprotectSource( unprotectRealComments( innerText ), editor ) + '</' + tagName + '>'; | 944 | return '<' + tagName + tagAttributes + '>' + unprotectSource( unprotectRealComments( innerText ), editor ) + '</' + tagName + '>'; |
928 | } ); | 945 | } ); |
@@ -971,7 +988,7 @@ | |||
971 | * {@link CKEDITOR.htmlParser.fragment} {@link CKEDITOR.htmlParser.element}. | 988 | * {@link CKEDITOR.htmlParser.fragment} {@link CKEDITOR.htmlParser.element}. |
972 | * * 5-9: Data is available in the parsed format, but {@link CKEDITOR.htmlDataProcessor#dataFilter} | 989 | * * 5-9: Data is available in the parsed format, but {@link CKEDITOR.htmlDataProcessor#dataFilter} |
973 | * is not applied yet. | 990 | * is not applied yet. |
974 | * * 6: Data is filtered with the {CKEDITOR.filter content filter}. | 991 | * * 6: Data is filtered with the {@link CKEDITOR.filter content filter}. |
975 | * * 10: Data is processed with {@link CKEDITOR.htmlDataProcessor#dataFilter}. | 992 | * * 10: Data is processed with {@link CKEDITOR.htmlDataProcessor#dataFilter}. |
976 | * * 10-14: Data is available in the parsed format and {@link CKEDITOR.htmlDataProcessor#dataFilter} | 993 | * * 10-14: Data is available in the parsed format and {@link CKEDITOR.htmlDataProcessor#dataFilter} |
977 | * has already been applied. | 994 | * has already been applied. |