Ticket #3582: 3582_12.patch
File 3582_12.patch, 21.3 KB (added by , 13 years ago) |
---|
-
_source/core/dom/element.js
429 429 name = 'className'; 430 430 break; 431 431 432 case 'name': 433 return this.$.name; 434 432 435 case 'tabindex': 433 436 var tabIndex = standard.call( this, name ); 434 437 … … 884 887 * @param {String} name The attribute name. 885 888 * @example 886 889 */ 887 hasAttribute : function( name)890 hasAttribute : (function() 888 891 { 889 var $attr = this.$.attributes.getNamedItem( name ); 890 return !!( $attr && $attr.specified ); 891 }, 892 function standard( name ) 893 { 894 var $attr = this.$.attributes.getNamedItem( name ); 895 return !!( $attr && $attr.specified ); 896 } 897 898 return ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) ? 899 function( name ) 900 { 901 // On IE < 8 the name attribute cannot be retrieved 902 // right after the element creation and setting the 903 // name with setAttribute. 904 if ( name == 'name' ) 905 return !!this.$.name; 892 906 907 return standard( name ); 908 } 909 : 910 standard; 911 })(), 912 893 913 /** 894 914 * Hides this element (display:none). 895 915 * @example -
_source/plugins/elementspath/plugin.js
124 124 125 125 while ( element ) 126 126 { 127 var ignore = 0; 127 var ignore = 0, 128 name; 129 130 if ( element.data( 'cke-real-element-type' ) ) 131 name = element.data( 'cke-real-element-type' ); 132 else 133 name = element.getName(); 134 128 135 for ( var i = 0; i < filters.length; i++ ) 129 136 { 130 if ( filters[ i ]( element ) === false ) 137 var ret = filters[ i ]( element, name ); 138 if ( ret === false ) 131 139 { 132 140 ignore = 1; 133 141 break; 134 142 } 143 name = ret || name; 135 144 } 136 145 137 146 if ( !ignore ) 138 147 { 139 148 var index = elementsList.push( element ) - 1; 140 var name;141 if ( element.data( 'cke-real-element-type' ) )142 name = element.data( 'cke-real-element-type' );143 else144 name = element.getName();145 149 146 150 // Use this variable to add conditional stuff to the 147 151 // HTML (because we are doing it in reverse order... unshift). -
_source/plugins/forms/plugin.js
261 261 262 262 if ( CKEDITOR.env.ie ) 263 263 { 264 CKEDITOR.dom.element.prototype.hasAttribute = function( name ) 265 { 266 var $attr = this.$.attributes.getNamedItem( name ); 267 268 if ( this.getName() == 'input' ) 264 CKEDITOR.dom.element.prototype.hasAttribute = CKEDITOR.tools.override( CKEDITOR.dom.element.prototype.hasAttribute, 265 function( original ) 269 266 { 270 switch ( name ) 271 { 272 case 'class' : 273 return this.$.className.length > 0; 274 case 'checked' : 275 return !!this.$.checked; 276 case 'value' : 277 var type = this.getAttribute( 'type' ); 278 return type == 'checkbox' || type == 'radio' ? this.$.value != 'on' : this.$.value; 279 } 280 } 267 return function( name ) 268 { 269 var $attr = this.$.attributes.getNamedItem( name ); 281 270 282 return !!( $attr && $attr.specified ); 283 }; 271 if ( this.getName() == 'input' ) 272 { 273 switch ( name ) 274 { 275 case 'class' : 276 return this.$.className.length > 0; 277 case 'checked' : 278 return !!this.$.checked; 279 case 'value' : 280 var type = this.getAttribute( 'type' ); 281 return type == 'checkbox' || type == 'radio' ? this.$.value != 'on' : this.$.value; 282 } 283 } 284 285 return original.apply( this, arguments ); 286 }; 287 }); 284 288 } -
_source/plugins/htmldataprocessor/plugin.js
95 95 delete blockLikeTags.pre; 96 96 var defaultDataFilterRules = 97 97 { 98 elements : { 99 a : function( element ) 100 { 101 var attrs = element.attributes; 102 if ( attrs && attrs[ 'data-cke-saved-name' ] ) 103 attrs[ 'class' ] = ( attrs[ 'class' ] ? attrs[ 'class' ] + ' ' : '' ) + 'cke_anchor'; 104 } 105 }, 98 elements : {}, 106 99 attributeNames : 107 100 [ 108 101 // Event attributes (onXYZ) must not be directly set. They can become -
_source/plugins/link/dialogs/anchor.js
6 6 CKEDITOR.dialog.add( 'anchor', function( editor ) 7 7 { 8 8 // Function called in onShow to load selected element. 9 var loadElements = function( e ditor, selection, element )9 var loadElements = function( element ) 10 10 { 11 this.editMode = true; 12 this.editObj = element; 11 this._.selectedElement = element; 13 12 14 var attributeValue = this.editObj.getAttribute( 'name' ); 15 if ( attributeValue ) 16 this.setValueOf( 'info','txtName', attributeValue ); 17 else 18 this.setValueOf( 'info','txtName', "" ); 13 var attributeValue = element.data( 'cke-saved-name' ); 14 this.setValueOf( 'info','txtName', attributeValue || '' ); 19 15 }; 20 16 17 function createFakeAnchor( editor, anchor ) 18 { 19 return editor.createFakeElement( anchor, 'cke_anchor', 'anchor' ); 20 } 21 21 22 return { 22 23 title : editor.lang.anchor.title, 23 24 minWidth : 300, 24 25 minHeight : 60, 25 26 onOk : function() 26 27 { 27 // Always create a new anchor, because of IE BUG. 28 var name = this.getValueOf( 'info', 'txtName' ), 29 element = CKEDITOR.env.ie && !( CKEDITOR.document.$.documentMode >= 8 ) ? 30 editor.document.createElement( '<a name="' + CKEDITOR.tools.htmlEncode( name ) + '">' ) : 31 editor.document.createElement( 'a' ); 28 var name = this.getValueOf( 'info', 'txtName' ); 29 var attributes = 30 { 31 name : name, 32 'data-cke-saved-name' : name 33 }; 32 34 33 // Move contents and attributes of old anchor to new anchor. 34 if ( this.editMode ) 35 if ( this._.selectedElement ) 35 36 { 36 this.editObj.copyAttributes( element, { name : 1 } ); 37 this.editObj.moveChildren( element ); 37 if ( this._.selectedElement.data( 'cke-realelement' ) ) 38 { 39 var newFake = createFakeAnchor( editor, editor.document.createElement( 'a', { attributes: attributes } ) ); 40 newFake.replace( this._.selectedElement ); 41 } 42 else 43 this._.selectedElement.setAttributes( attributes ); 38 44 } 45 else 46 { 47 var sel = editor.getSelection(), 48 range = sel && sel.getRanges()[ 0 ]; 39 49 40 // Set name. 41 element.data( 'cke-saved-name', false ); 42 element.setAttribute( 'name', name ); 50 // Empty anchor 51 if ( range.collapsed ) 52 { 53 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) 54 attributes['class'] = 'cke_anchor_empty'; 43 55 44 // Insert a new anchor. 45 var fakeElement = editor.createFakeElement( element, 'cke_anchor', 'anchor' ); 46 if ( !this.editMode ) 47 editor.insertElement( fakeElement ); 48 else 49 { 50 fakeElement.replace( this.fakeObj ); 51 editor.getSelection().selectElement( fakeElement ); 56 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) 57 { 58 attributes[ 'contenteditable' ] = 'false'; 59 attributes[ 'data-cke-editable' ] = 1; 60 } 61 62 var anchor = editor.document.createElement( 'a', { attributes: attributes } ); 63 64 // Transform the anchor into a fake element for browsers that need it. 65 if ( CKEDITOR.plugins.link.fakeAnchor ) 66 anchor = createFakeAnchor( editor, anchor ); 67 68 range.insertNode( anchor ); 69 } 70 else 71 { 72 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) 73 attributes['class'] = 'cke_anchor'; 74 75 // Apply style. 76 var style = new CKEDITOR.style( { element : 'a', attributes : attributes } ); 77 style.type = CKEDITOR.STYLE_INLINE; 78 style.apply( editor.document ); 79 } 52 80 } 81 }, 53 82 54 return true; 83 onHide : function() 84 { 85 delete this._.selectedElement; 55 86 }, 87 56 88 onShow : function() 57 89 { 58 this.editObj = false;59 this.fakeObj = false;60 this.editMode = false;90 var selection = editor.getSelection(), 91 fullySelected = selection.getSelectedElement(), 92 partialSelected; 61 93 62 var selection = editor.getSelection(); 63 var element = selection.getSelectedElement(); 64 if ( element && element.data( 'cke-real-element-type' ) && element.data( 'cke-real-element-type' ) == 'anchor' ) 94 // Detect the anchor under selection. 95 if ( fullySelected ) 65 96 { 66 this.fakeObj = element; 67 element = editor.restoreRealElement( this.fakeObj ); 68 loadElements.apply( this, [ editor, selection, element ] ); 69 selection.selectElement( this.fakeObj ); 97 if ( CKEDITOR.plugins.link.fakeAnchor ) 98 { 99 var realElement = CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, fullySelected ); 100 realElement && loadElements.call( this, realElement ); 101 this._.selectedElement = fullySelected; 102 } 103 else if ( fullySelected.is( 'a' ) && fullySelected.hasAttribute( 'name' ) ) 104 loadElements.call( this, fullySelected ); 70 105 } 106 else 107 { 108 partialSelected = CKEDITOR.plugins.link.getSelectedLink( editor ); 109 if ( partialSelected ) 110 { 111 loadElements.call( this, partialSelected ); 112 selection.selectElement( partialSelected ); 113 } 114 } 115 71 116 this.getContentElement( 'info', 'txtName' ).focus(); 72 117 }, 73 118 contents : [ -
_source/plugins/link/dialogs/link.js
235 235 advAttr( 'advTabIndex', 'tabindex' ); 236 236 advAttr( 'advTitle', 'title' ); 237 237 advAttr( 'advContentType', 'type' ); 238 advAttr( 'advCSSClasses', 'class' );239 238 advAttr( 'advCharset', 'charset' ); 240 239 advAttr( 'advStyles', 'style' ); 241 240 advAttr( 'advRel', 'rel' ); 241 242 retval.adv.advCSSClasses = getLinkClass( element ) || ''; 242 243 } 243 244 244 245 // Find out whether we have any anchors in the editor. 245 // Get all IMG elements in CK document. 246 var elements = editor.document.getElementsByTag( 'img' ), 247 realAnchors = new CKEDITOR.dom.nodeList( editor.document.$.anchors ), 248 anchors = retval.anchors = []; 246 var anchorList = new CKEDITOR.dom.nodeList( editor.document.$.anchors ), 247 anchors = retval.anchors = [], 248 item; 249 249 250 for ( var i = 0 ; i < elements.count(); i++ )250 for ( var i = 0, count = anchorList.count(); i < count; i++ ) 251 251 { 252 var item = elements.getItem( i ); 253 if ( item.data( 'cke-realelement' ) && item.data( 'cke-real-element-type' ) == 'anchor' ) 254 anchors.push( editor.restoreRealElement( item ) ); 255 } 256 257 for ( i = 0 ; i < realAnchors.count() ; i++ ) 258 anchors.push( realAnchors.getItem( i ) ); 259 260 for ( i = 0 ; i < anchors.length ; i++ ) 261 { 262 item = anchors[ i ]; 252 item = anchorList.getItem( i ); 263 253 anchors[ i ] = { name : item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) }; 264 254 } 265 255 266 256 // Record down the selected element in the dialog. 267 257 this._.selectedElement = element; 268 269 258 return retval; 270 259 }; 271 260 … … 369 358 return 'String.fromCharCode(' + encodedChars.join( ',' ) + ')'; 370 359 } 371 360 361 function getLinkClass( ele ) 362 { 363 var className = ele.getAttribute( 'class' ); 364 return className ? className.replace( /\s*(?:cke_anchor_empty|cke_anchor)(?:\s*$)?/g, '' ) : ''; 365 } 366 372 367 var commonLang = editor.lang.common, 373 368 linkLang = editor.lang.link; 374 369 … … 1151 1146 ], 1152 1147 onShow : function() 1153 1148 { 1154 this.fakeObj = false;1155 1156 1149 var editor = this.getParentEditor(), 1157 1150 selection = editor.getSelection(), 1158 1151 element = null; … … 1160 1153 // Fill in all the relevant fields if there's already one link selected. 1161 1154 if ( ( element = plugin.getSelectedLink( editor ) ) && element.hasAttribute( 'href' ) ) 1162 1155 selection.selectElement( element ); 1163 else if ( ( element = selection.getSelectedElement() ) && element.is( 'img' )1164 && element.data( 'cke-real-element-type' )1165 && element.data( 'cke-real-element-type' ) == 'anchor' )1166 {1167 this.fakeObj = element;1168 element = editor.restoreRealElement( this.fakeObj );1169 selection.selectElement( this.fakeObj );1170 }1171 1156 else 1172 1157 element = null; 1173 1158 … … 1302 1287 advAttr( 'advAccessKey', 'accessKey' ); 1303 1288 1304 1289 if ( data.adv[ 'advName' ] ) 1305 {1306 1290 attributes[ 'name' ] = attributes[ 'data-cke-saved-name' ] = data.adv[ 'advName' ]; 1307 attributes[ 'class' ] = ( attributes[ 'class' ] ? attributes[ 'class' ] + ' ' : '' ) + 'cke_anchor';1308 }1309 1291 else 1310 1292 removeAttributes = removeAttributes.concat( [ 'data-cke-saved-name', 'name' ] ); 1311 1293 … … 1350 1332 href = element.data( 'cke-saved-href' ), 1351 1333 textView = element.getHtml(); 1352 1334 1353 // IE BUG: Setting the name attribute to an existing link doesn't work.1354 // Must re-create the link from weired syntax to workaround.1355 if ( CKEDITOR.env.ie && !( CKEDITOR.document.$.documentMode >= 8 ) && attributes.name != element.getAttribute( 'name' ) )1356 {1357 var newElement = new CKEDITOR.dom.element( '<a name="' + CKEDITOR.tools.htmlEncode( attributes.name ) + '">',1358 editor.document );1359 1360 selection = editor.getSelection();1361 1362 element.copyAttributes( newElement, { name : 1 } );1363 element.moveChildren( newElement );1364 newElement.replace( element );1365 element = newElement;1366 1367 selection.selectElement( element );1368 }1369 1370 1335 element.setAttributes( attributes ); 1371 1336 element.removeAttributes( removeAttributes ); 1337 1338 if ( data.adv && data.adv.advName ) 1339 element.addClass( element.getChildCount() ? 'cke_anchor' : 'cke_anchor_empty' ); 1340 1372 1341 // Update text view when user changes protocol (#4612). 1373 1342 if ( href == textView || data.type == 'email' && textView.indexOf( '@' ) != -1 ) 1374 1343 { … … 1376 1345 element.setHtml( data.type == 'email' ? 1377 1346 data.email.address : attributes[ 'data-cke-saved-href' ] ); 1378 1347 } 1379 // Make the element display as an anchor if a name has been set.1380 if ( element.getAttribute( 'name' ) )1381 element.addClass( 'cke_anchor' );1382 else1383 element.removeClass( 'cke_anchor' );1384 1348 1385 if ( this.fakeObj )1386 editor.createFakeElement( element, 'cke_anchor', 'anchor' ).replace( this.fakeObj );1387 1388 1349 delete this._.selectedElement; 1389 1350 } 1390 1351 }, -
_source/plugins/link/plugin.js
30 30 CKEDITOR.dialog.add( 'anchor', this.path + 'dialogs/anchor.js' ); 31 31 32 32 // Add the CSS styles for anchor placeholders. 33 var side = editor.lang.dir == 'rtl' ? 'right' : 'left'; 33 34 var side = ( editor.lang.dir == 'rtl' ? 'right' : 'left' ); 35 var basicCss = 36 'background:url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ') no-repeat ' + side + ' center;' + 37 'border:1px dotted #00f;'; 38 34 39 editor.addCss( 40 'a.cke_anchor,a.cke_anchor_empty' + 41 // IE6 breaks with the following selectors. 42 ( ( CKEDITOR.env.ie && CKEDITOR.env.version < 7 ) ? '' : 43 ',a[name],a[data-cke-saved-name]' ) + 44 '{' + 45 basicCss + 46 'padding-' + side + ':18px;' + 47 // Show the arrow cursor for the anchor image (FF at least). 48 'cursor:auto;' + 49 '}' + 50 ( ( CKEDITOR.env.ie && CKEDITOR.env.version > 8 ) ? 'a[name]:empty,' : '' ) + 51 'a.cke_anchor_empty' + 52 '{' + 53 // Make empty anchor selectable on IE. 54 'display:inline-block;' + 55 '}' + 35 56 'img.cke_anchor' + 36 57 '{' + 37 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' + 38 'background-position: center center;' + 39 'background-repeat: no-repeat;' + 40 'border: 1px solid #a9a9a9;' + 41 'width: 18px !important;' + 42 'height: 18px !important;' + 43 '}\n' + 44 'a.cke_anchor' + 45 '{' + 46 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' + 47 'background-position: ' + side + ' center;' + 48 'background-repeat: no-repeat;' + 49 'border: 1px solid #a9a9a9;' + 50 'padding-' + side + ': 18px;' + 51 '}' 52 ); 58 basicCss + 59 'width:16px;' + 60 'min-height:15px;' + 61 // The default line-height on IE. 62 'height:1.15em;' + 63 // Opera works better with "middle" (even if not perfect) 64 'vertical-align:' + ( CKEDITOR.env.opera ? 'middle' : 'text-bottom' ) + ';' + 65 '}'); 53 66 54 67 // Register selection change handler for the unlink button. 55 68 editor.on( 'selectionChange', function( evt ) … … 73 86 if ( !element.isReadOnly() ) 74 87 { 75 88 if ( element.is( 'a' ) ) 76 evt.data.dialog = ( element.getAttribute( 'name' ) && !element.getAttribute( 'href' ) ) ? 'anchor' : 'link'; 77 else if ( element.is( 'img' ) && element.data( 'cke-real-element-type' ) == 'anchor' ) 89 { 90 evt.data.dialog = ( element.getAttribute( 'name' ) && !element.getAttribute( 'href' ) ) ? 'anchor' : 'link'; 91 editor.getSelection().selectElement( element ); 92 } 93 else if ( CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, element ) ) 78 94 evt.data.dialog = 'anchor'; 79 95 } 80 96 }); … … 117 133 if ( !element || element.isReadOnly() ) 118 134 return null; 119 135 120 var isAnchor = ( element.is( 'img' ) && element.data( 'cke-real-element-type' ) == 'anchor');136 var anchor = CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, element ); 121 137 122 if ( !isAnchor ) 123 { 124 if ( !( element = CKEDITOR.plugins.link.getSelectedLink( editor ) ) ) 138 if ( !anchor && !( anchor = CKEDITOR.plugins.link.getSelectedLink( editor ) ) ) 125 139 return null; 126 140 127 isAnchor = ( element.getAttribute( 'name' ) && !element.getAttribute( 'href' ) ); 128 } 141 var menu = {}; 129 142 130 return isAnchor ? 131 { anchor : CKEDITOR.TRISTATE_OFF } : 132 { link : CKEDITOR.TRISTATE_OFF, unlink : CKEDITOR.TRISTATE_OFF }; 143 if ( anchor.getAttribute( 'href' ) && anchor.getChildCount() ) 144 menu = { link : CKEDITOR.TRISTATE_OFF, unlink : CKEDITOR.TRISTATE_OFF }; 145 146 if ( anchor && anchor.hasAttribute( 'name' ) ) 147 menu.anchor = CKEDITOR.TRISTATE_OFF; 148 149 return menu; 133 150 }); 134 151 } 135 152 }, … … 139 156 // Register a filter to displaying placeholders after mode change. 140 157 141 158 var dataProcessor = editor.dataProcessor, 142 dataFilter = dataProcessor && dataProcessor.dataFilter; 159 dataFilter = dataProcessor && dataProcessor.dataFilter, 160 htmlFilter = dataProcessor && dataProcessor.htmlFilter, 161 pathFilters = editor._.elementsPath.filters; 143 162 144 163 if ( dataFilter ) 145 164 { … … 150 169 a : function( element ) 151 170 { 152 171 var attributes = element.attributes; 153 if ( attributes.name && !attributes.href ) 172 if ( !attributes.name ) 173 return; 174 175 var isEmpty = !element.children.length; 176 177 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) 178 { 179 // IE needs a specific class name to be applied 180 // to the anchors, for appropriate styling. 181 var ieClass = isEmpty ? 'cke_anchor_empty' : 'cke_anchor'; 182 var cls = attributes[ 'class' ]; 183 if ( attributes.name && ( !cls || cls.indexOf( ieClass ) < 0 ) ) 184 attributes[ 'class' ] = ( cls || '' ) + ' ' + ieClass; 185 186 if ( isEmpty && CKEDITOR.env.version < 8 ) 187 { 188 attributes.contenteditable = 'false'; 189 attributes[ 'data-cke-editable' ] = 1; 190 } 191 } 192 else if ( CKEDITOR.plugins.link.fakeAnchor && isEmpty ) 154 193 return editor.createFakeParserElement( element, 'cke_anchor', 'anchor' ); 155 194 } 156 195 } 157 196 }); 158 197 } 198 199 if ( CKEDITOR.env.ie && htmlFilter ) 200 { 201 htmlFilter.addRules( 202 { 203 elements : 204 { 205 a : function( element ) 206 { 207 delete element.attributes.contenteditable; 208 } 209 } 210 }); 211 } 212 213 if ( pathFilters ) 214 { 215 pathFilters.push( function( element, name ) 216 { 217 if ( name == 'a' ) 218 { 219 if ( CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, element ) || 220 ( element.getAttribute( 'name' ) && !element.getAttribute( 'href' ) ) ) 221 { 222 return 'anchor'; 223 } 224 } 225 }); 226 } 159 227 }, 160 228 161 229 requires : [ 'fakeobjects' ] … … 196 264 return root.getAscendant( 'a', true ); 197 265 } 198 266 catch( e ) { return null; } 267 }, 268 269 // Opera and WebKit don't make it possible to select empty anchors. Fake 270 // elements must be used for them. 271 fakeAnchor : CKEDITOR.env.opera || CKEDITOR.env.webkit, 272 273 tryRestoreFakeAnchor : function( editor, element ) 274 { 275 if ( element && element.data( 'cke-real-element-type' ) && element.data( 'cke-real-element-type' ) == 'anchor' ) 276 { 277 var link = editor.restoreRealElement( element ); 278 if ( link.data( 'cke-saved-name' ) ) 279 return link; 280 } 199 281 } 200 282 }; 201 283