Ticket #3074: 3074_2.patch
File 3074_2.patch, 18.9 KB (added by , 15 years ago) |
---|
-
_source/plugins/dialogui/plugin.js
208 208 attributes.size = elementDefinition.size; 209 209 210 210 // If user presses Enter in a text box, it implies clicking OK for the dialog. 211 var me = this ;211 var me = this, keyPressedOnMe = false; 212 212 dialog.on( 'load', function() 213 213 { 214 me.getInputElement().on( 'keydown', function( evt ) 215 { 216 if ( evt.data.getKeystroke() == 13 ) 217 keyPressedOnMe = true; 218 } ); 214 219 me.getInputElement().on( 'keyup', function( evt ) 215 220 { 216 if ( evt.data.$.keyCode == 13 ) 221 if ( evt.data.getKeystroke() == 13 && keyPressedOnMe ) 222 { 217 223 dialog.getButton( 'ok' ) && dialog.getButton( 'ok' ).click(); 224 keyPressedOnMe = false; 225 } 218 226 } ); 219 227 } ); 220 228 … … 436 444 /** @ignore */ 437 445 var innerHTML = function() 438 446 { 439 return [ '<tbody><tr><td class="cke_dialog_ui_button_txt">', 440 CKEDITOR.tools.htmlEncode( elementDefinition.label ), 441 '</td></tr></tbody>' ].join( '' ); 447 var styles = [], 448 align = elementDefinition.align || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' ); 449 450 if ( elementDefinition.style ) 451 { 452 var defStyle = CKEDITOR.tools.trim( elementDefinition.style ); 453 styles.push( defStyle ); 454 if ( defStyle.charAt( defStyle.length - 1 ) != ';' ) 455 styles.push( ';' ); 456 } 457 458 // IE6 & 7 BUG: Need to set margin as well as align. 459 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) 460 { 461 styles.push( [ 462 'margin:', 463 'auto', 464 align == 'right' ? '0px' : 'auto', 465 'auto', 466 align == 'left' ? '0px' : 'auto' ].join( ' ' ), ';' ); 467 } 468 469 return [ 470 '<table align="', align, '" ', styles.length > 0 ? 'style="' + styles.join( '' ) + '">' : '>', 471 '<tbody><tr><td class="cke_dialog_ui_button_txt">', 472 CKEDITOR.tools.htmlEncode( elementDefinition.label ), 473 '</td></tr></tbody></table>' 474 ].join( '' ); 442 475 }; 443 476 444 477 // Add OnClick event to this input. … … 449 482 dialog.on( 'load', function( eventInfo ) 450 483 { 451 484 var element = this.getElement(); 452 element.on( 'mousedown', function( evt ) 453 { 454 // If button is disabled, don't do anything. 455 if ( me._.disabled ) 456 return; 485 (function() 486 { 487 element.on( 'mousedown', function( evt ) 488 { 489 // If button is disabled, don't do anything. 490 if ( me._.disabled ) 491 return; 457 492 458 // Change styles to indicate the button is being clicked. 459 me.getElement().addClass( 'active' ); 493 // Store the currently active button. 494 CKEDITOR.ui.dialog.button._.activeButton = [ me, me.getElement() ]; 495 } ); 460 496 461 // Store the currently active button. 462 CKEDITOR.ui.dialog.button._.activeButton = [ me, me.getElement() ]; 463 }); 497 element.on( 'keydown', function( evt ) 498 { 499 // Click if Enter is pressed. 500 if ( evt.data.$.keyCode == 13 ) 501 { 502 me.fire( 'click', { dialog : me.getDialog() } ); 503 evt.data.preventDefault(); 504 } 505 } ); 506 })(); 464 507 465 508 // IE BUG: Padding attributes are ignored for <td> cells. 466 509 if ( CKEDITOR.env.ie ) 467 element.getChild( [0, 0, 0 ] ).$.innerHTML += '';510 element.getChild( [0, 0, 0, 0] ).$.innerHTML += ''; 468 511 469 512 if ( !eventInfo.data.buttonHandlerRegistered ) 470 513 { … … 477 520 if ( !activeButton ) 478 521 return; 479 522 480 // Change styles to remove active status.481 activeButton[1].removeClass( 'active' );482 483 523 // Fire the click event - but only if the 484 524 // active button is the same as target. 485 if ( activeButton[1].equals( target.getAscendant( ' table' ) ) )525 if ( activeButton[1].equals( target.getAscendant( 'a' ) ) ) 486 526 activeButton[0].fire( 'click', { dialog : activeButton[0].getDialog() } ); 487 527 488 528 // Clear active button flag. 489 529 CKEDITOR.ui.dialog.button._.activeButton = null; 490 } );530 } ); 491 531 492 532 eventInfo.data.buttonHandlerRegistered = true; 493 533 } 494 534 495 this.getElement(). unselectable();535 this.getElement().getFirst().unselectable(); 496 536 }, this ); 497 537 498 var styles = {},499 align = elementDefinition.align || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' );538 var outerDefinition = CKEDITOR.tools.extend( {}, elementDefinition ); 539 delete outerDefinition.style; 500 540 501 // IE6 & 7 BUG: Need to set margin as well as align. 502 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) 503 { 504 styles.margin = [ 505 'auto', 506 align == 'right' ? '0px' : 'auto', 507 'auto', 508 align == 'left' ? '0px' : 'auto' ].join( ' ' ); 509 } 510 511 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, htmlList, 'table', styles, 512 { align : align }, innerHTML ); 541 CKEDITOR.ui.dialog.uiElement.call( this, dialog, outerDefinition, htmlList, 'a', { display : 'block', outline : 'none' }, 542 { href : 'javascript:void(0);', title : elementDefinition.label, hidefocus : 'true' }, 543 innerHTML ); 513 544 }, 514 545 515 546 /** … … 779 810 { 780 811 if ( !this._.disabled ) 781 812 return this.fire( 'click', { dialog : this._.dialog } ); 813 this.getElement().$.blur(); 782 814 }, 783 815 784 816 /** … … 801 833 this.getElement().addClass( 'disabled' ); 802 834 }, 803 835 836 isVisible : function() 837 { 838 return !!this.getElement().$.firstChild.offsetHeight; 839 }, 840 841 isEnabled : function() 842 { 843 return !this._.disabled; 844 }, 845 804 846 /** 805 847 * Defines the onChange event and onClick for button element definitions. 806 848 * @field … … 823 865 */ 824 866 accessKeyUp : function() 825 867 { 826 this.getElement().removeClass( 'active' );827 868 this.click(); 828 869 }, 829 870 … … 834 875 */ 835 876 accessKeyDown : function() 836 877 { 837 this.getElement().addClass( 'active' ); 838 } 878 this.focus(); 879 }, 880 881 keyboardFocusable : true 839 882 }, true ); 840 883 841 884 CKEDITOR.ui.dialog.textInput.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement, … … 896 939 { 897 940 value = value || ''; 898 941 return CKEDITOR.ui.dialog.uiElement.prototype.setValue.call( this, value ); 899 } 942 }, 943 944 keyboardFocusable : true 900 945 }, commonPrototype, true ); 901 946 902 947 CKEDITOR.ui.dialog.textarea.prototype = new CKEDITOR.ui.dialog.textInput(); … … 966 1011 while ( selectElement.length > 0 ) 967 1012 selectElement.remove( 0 ); 968 1013 return this; 969 } 1014 }, 1015 1016 keyboardFocusable : true 970 1017 }, commonPrototype, true ); 971 1018 972 1019 CKEDITOR.ui.dialog.checkbox.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement, … … 1040 1087 } 1041 1088 return null; 1042 1089 } 1043 } 1090 }, 1091 1092 keyboardFocusable : true 1044 1093 }, commonPrototype, true ); 1045 1094 1046 1095 CKEDITOR.ui.dialog.radio.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement, … … 1128 1177 } 1129 1178 return null; 1130 1179 } 1131 } 1180 }, 1181 1182 keyboardFocusable : true 1132 1183 }, commonPrototype, true ); 1133 1184 1134 1185 CKEDITOR.ui.dialog.file.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement, … … 1193 1244 * @type Object 1194 1245 * @example 1195 1246 */ 1196 eventProcessors : commonEventProcessors 1247 eventProcessors : commonEventProcessors, 1248 1249 keyboardFocusable : true 1197 1250 }, true ); 1198 1251 1199 1252 CKEDITOR.ui.dialog.fileButton.prototype = new CKEDITOR.ui.dialog.button; -
_source/plugins/dialog/plugin.js
38 38 39 39 (function() 40 40 { 41 function isTabVisible( tabId ) 42 { 43 return !!this._.tabs[ tabId ][ 0 ].$.offsetHeight; 44 } 45 46 function getPreviousVisibleTab() 47 { 48 var tabId = this._.currentTabId, 49 length = this._.tabIdList.length, 50 tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId ) + length; 51 52 for ( var i = tabIndex - 1 ; i > tabIndex - length ; i-- ) 53 { 54 if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) ) 55 return this._.tabIdList[ i % length ]; 56 } 57 58 return null; 59 } 60 61 function getNextVisibleTab() 62 { 63 var tabId = this._.currentTabId, 64 length = this._.tabIdList.length, 65 tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId ); 66 67 for ( var i = tabIndex + 1 ; i < tabIndex + length ; i++ ) 68 { 69 if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) ) 70 return this._.tabIdList[ i % length ]; 71 } 72 73 return null; 74 } 75 41 76 /** 42 77 * This is the base class for runtime dialog objects. An instance of this 43 78 * class represents a single named dialog for a single editor instance. … … 88 123 89 124 // Initialize the tab and page map. 90 125 tabs : {}, 126 tabIdList : [], 127 currentTabId : null, 128 currentTabIndex : null, 91 129 pageCount : 0, 92 lastTab : null 130 lastTab : null, 131 tabBarMode : false, 132 133 // Initialize the tab order array for input widgets. 134 focusList : [], 135 currentFocusIndex : 0, 136 hasFocus : false 93 137 }; 94 138 95 139 /** … … 251 295 this.hide(); 252 296 }, this ); 253 297 298 function changeFocus( forward ) 299 { 300 var focusList = me._.focusList, 301 offset = forward ? 1 : -1; 302 if ( focusList.length < 1 ) 303 return; 304 305 var currentIndex = ( me._.currentFocusIndex + offset + focusList.length ) % focusList.length; 306 while ( !focusList[ currentIndex ].isFocusable() ) 307 { 308 currentIndex = ( currentIndex + offset + focusList.length ) % focusList.length; 309 if ( currentIndex == me._.currentFocusIndex ) 310 break; 311 } 312 focusList[ currentIndex ].focus(); 313 } 314 315 function focusKeydownHandler( evt ) 316 { 317 // If I'm not the top dialog, ignore. 318 if ( me != CKEDITOR.dialog._.currentTop ) 319 return; 320 321 var keystroke = evt.data.getKeystroke(), 322 processed = false; 323 if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 ) 324 { 325 var shiftPressed = ( keystroke == CKEDITOR.SHIFT + 9 ); 326 327 // Handling Tab and Shift-Tab. 328 if ( me._.tabBarMode ) 329 { 330 // Change tabs. 331 var nextId = shiftPressed ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ); 332 me.selectPage( nextId ); 333 me._.tabs[ nextId ][ 0 ].getFirst().focus(); 334 } 335 else 336 { 337 // Change the focus of inputs. 338 changeFocus( !shiftPressed ); 339 } 340 341 processed = true; 342 } 343 else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode ) 344 { 345 // Alt-F10 puts focus into the current tab item in the tab bar. 346 me._.tabBarMode = true; 347 me._.tabs[ me._.currentTabId ][ 0 ].getFirst().focus(); 348 processed = true; 349 } 350 else if ( ( keystroke == 37 || keystroke == 39 ) && me._.tabBarMode ) 351 { 352 // Arrow keys - used for changing tabs. 353 var nextId = ( keystroke == 37 ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) ); 354 me.selectPage( nextId ); 355 me._.tabs[ nextId ][ 0 ].getFirst().focus(); 356 processed = true; 357 } 358 359 if ( processed ) 360 { 361 evt.stop(); 362 evt.data.preventDefault(); 363 } 364 } 365 366 // Add the dialog keyboard handlers. 367 this.on( 'show', function() 368 { 369 CKEDITOR.document.on( 'keydown', focusKeydownHandler, this, null, 0 ); 370 if ( CKEDITOR.env.ie6Compat ) 371 { 372 var coverDoc = new CKEDITOR.dom.document( frames( 'cke_dialog_background_iframe' ).document ); 373 coverDoc.on( 'keydown', focusKeydownHandler, this, null, 0 ); 374 } 375 } ); 376 this.on( 'hide', function() 377 { 378 CKEDITOR.document.removeListener( 'keydown', focusKeydownHandler ); 379 } ); 380 381 // Auto-focus logic in dialog. 382 this.on( 'show', function() 383 { 384 if ( !this._.hasFocus ) 385 { 386 this._.currentFocusIndex = -1; 387 changeFocus( true ); 388 } 389 }, this, null, 0xffffffff ); 390 254 391 // IE6 BUG: Text fields and text areas are only half-rendered the first time the dialog appears in IE6 (#2661). 255 392 // This is still needed after [2708] and [2709] because text fields in hidden TR tags are still broken. 256 393 if ( CKEDITOR.env.ie6Compat ) … … 281 418 var target = evt.data.getTarget(), firstNode = target, id, page; 282 419 283 420 // If we aren't inside a tab, bail out. 284 if ( ! tabRegex.test( target.$.className) )421 if ( !( tabRegex.test( target.$.className ) || target.getName() == 'a' ) ) 285 422 return; 286 423 287 424 // Find the outer <td> container of the tab. … … 291 428 } 292 429 id = target.$.id.substr( 0, target.$.id.lastIndexOf( '_' ) ); 293 430 this.selectPage( id ); 431 432 if ( this._.tabBarMode ) 433 { 434 this._.tabBarMode = false; 435 this._.currentFocusIndex = -1; 436 changeFocus( true ); 437 } 294 438 }, this ); 295 439 296 440 // Insert buttons. … … 466 610 this._.dummyText.focus(); 467 611 this._.dummyText.$.select(); 468 612 613 // Reset the hasFocus state. 614 this._.hasFocus = false; 615 469 616 // Execute onLoad for the first show. 470 617 this.fireOnce( 'load', {} ); 471 618 this.fire( 'show', {} ); … … 577 724 addPage : function( contents ) 578 725 { 579 726 var pageHtml = [], 580 titleHtml = contents. title ? 'title="' + CKEDITOR.tools.htmlEncode( contents.title ) + '"' : '',727 titleHtml = contents.label ? ' title="' + CKEDITOR.tools.htmlEncode( contents.label ) + '"' : '', 581 728 elements = contents.elements, 582 729 vbox = CKEDITOR.dialog._.uiElementBuilders.vbox.build( this, 583 730 { … … 590 737 // Create the HTML for the tab and the content block. 591 738 var page = CKEDITOR.dom.element.createFromHtml( pageHtml.join( '' ) ); 592 739 var tab = CKEDITOR.dom.element.createFromHtml( [ 593 '<table><tbody><tr><td class="cke_dialog_tab" ', titleHtml, '>', 740 '<table><tbody><tr><td class="cke_dialog_tab">', 741 '<a href="javascript: void(0)"', titleHtml, ' style="display: block; outline: none;" hidefocus="true">', 594 742 '<table border="0" cellspacing="0" cellpadding="0"><tbody><tr>', 595 743 '<td class="cke_dialog_tab_left"></td>', 596 744 '<td class="cke_dialog_tab_center">', 597 745 CKEDITOR.tools.htmlEncode( contents.label.replace( / /g, '\xa0' ) ), 598 746 '</td>', 599 747 '<td class="cke_dialog_tab_right"></td>', 600 '</tr></tbody></table></ td></tr></tbody></table>'748 '</tr></tbody></table></a></td></tr></tbody></table>' 601 749 ].join( '' ) ); 602 750 tab = tab.getChild( [0,0,0] ); 603 751 … … 614 762 615 763 // Take records for the tabs and elements created. 616 764 this._.tabs[ contents.id ] = [ tab, page ]; 765 this._.tabIdList.push( contents.id ); 617 766 this._.pageCount++; 618 767 this._.lastTab = tab; 619 768 var contentMap = this._.contents[ contents.id ] = {}, … … 665 814 var selected = this._.tabs[id]; 666 815 selected[0].addClass( 'cke_dialog_tab_selected' ); 667 816 selected[1].show(); 668 var me = this; 817 this._.currentTabId = id; 818 this._.currentTabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, id ); 669 819 }, 670 820 671 821 /** … … 1671 1821 */ 1672 1822 uiElement : function( dialog, elementDefinition, htmlList, nodeNameArg, stylesArg, attributesArg, contentsArg ) 1673 1823 { 1674 if ( arguments.length < 4 )1824 if ( arguments.length < 4 ) 1675 1825 return; 1676 1826 1677 1827 var nodeName = ( nodeNameArg.call ? nodeNameArg( elementDefinition ) : nodeNameArg ) || 'div', … … 1744 1894 if ( this.accessKeyUp && this.accessKeyDown && elementDefinition.accessKey ) 1745 1895 registerAccessKey( this, dialog, 'CTRL+' + elementDefinition.accessKey ); 1746 1896 1897 var me = this; 1898 dialog.on( 'load', function() 1899 { 1900 if ( me.getInputElement() ) 1901 { 1902 me.getInputElement().on( 'focus', function() 1903 { 1904 dialog._.tabBarMode = false; 1905 dialog._.hasFocus = true; 1906 me.fire( 'focus' ); 1907 }, me ); 1908 } 1909 } ); 1910 1911 // Register the object as a tab focus if it can be included. 1912 if ( this.keyboardFocusable ) 1913 { 1914 this.focusIndex = dialog._.focusList.push( this ) - 1; 1915 this.on( 'focus', function() 1916 { 1917 dialog._.currentFocusIndex = me.focusIndex; 1918 } ); 1919 } 1920 1747 1921 // Completes this object with everything we have in the 1748 1922 // definition. 1749 1923 CKEDITOR.tools.extend( this, elementDefinition ); … … 1993 2167 while ( ( cursor = cursor.getParent() ) && cursor.$.className.search( 'cke_dialog_page_contents' ) == -1 ) 1994 2168 { /*jsl:pass*/ } 1995 2169 2170 // Some widgets don't have parent tabs (e.g. OK and Cancel buttons). 2171 if ( !cursor ) 2172 return this; 2173 1996 2174 tabId = cursor.getAttribute( 'name' ); 1997 2175 1998 2176 this._.dialog.selectPage( tabId ); … … 2147 2325 var element = this.getInputElement(); 2148 2326 element.removeAttribute( 'disabled' ); 2149 2327 element.removeClass( 'cke_disabled' ); 2328 }, 2329 2330 /** 2331 * Determines whether an UI element is enabled or not. 2332 * @returns {Boolean} Whether the UI element is enabled. 2333 * @example 2334 */ 2335 isEnabled : function() 2336 { 2337 return !this.getInputElement().getAttribute( 'disabled' ); 2338 }, 2339 2340 /** 2341 * Determines whether an UI element is visible or not. 2342 * @returns {Boolean} Whether the UI element is visible. 2343 * @example 2344 */ 2345 isVisible : function() 2346 { 2347 return !!this.getInputElement().$.offsetHeight; 2348 }, 2349 2350 /** 2351 * Determines whether an UI element is focus-able or not. 2352 * Focus-able is defined as being both visible and enabled. 2353 * @returns {Boolean} Whether the UI element can be focused. 2354 * @example 2355 */ 2356 isFocusable : function() 2357 { 2358 if ( !this.isEnabled() || !this.isVisible() ) 2359 return false; 2360 return true; 2150 2361 } 2151 2362 }; 2152 2363 -
_source/skins/default/dialog.css
375 375 vertical-align: top; 376 376 } 377 377 378 .cke_skin_default .cke_dialog_ui_button 378 .cke_skin_default .cke_dialog_ui_button table 379 379 { 380 380 border: #737357 1px solid; 381 381 } 382 382 383 .cke_skin_default .cke_dialog_ui_button.disabled 383 .cke_skin_default .cke_dialog_ui_button.disabled table 384 384 { 385 385 border: #898980 1px solid; 386 386 } … … 399 399 background-color: #c5c5b3; 400 400 } 401 401 402 .cke_skin_default .cke_dialog_ui_button.active .cke_dialog_ui_button_txt 402 .cke_skin_default a:focus.cke_dialog_ui_button .cke_dialog_ui_button_txt, 403 .cke_skin_default a:active.cke_dialog_ui_button .cke_dialog_ui_button_txt 403 404 { 404 405 background-color: #e3e3c7; 405 406 }