JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.6.3
[ckeditor.git] / _source / plugins / colordialog / dialogs / colordialog.js
index e83b62c..a8e83f5 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.html or http://ckeditor.com/license\r
 */\r
 \r
@@ -8,53 +8,229 @@ CKEDITOR.dialog.add( 'colordialog', function( editor )
                // Define some shorthands.\r
                var $el = CKEDITOR.dom.element,\r
                        $doc = CKEDITOR.document,\r
-                       $tools = CKEDITOR.tools,\r
                        lang = editor.lang.colordialog;\r
 \r
                // Reference the dialog.\r
                var dialog;\r
 \r
-               function spacer()\r
+               var spacer =\r
                {\r
-                       return {\r
-                               type : 'html',\r
-                               html : ' '\r
-                       };\r
+                       type : 'html',\r
+                       html : ' '\r
+               };\r
+\r
+               var selected;\r
+\r
+               function clearSelected()\r
+               {\r
+                       $doc.getById( selHiColorId ).removeStyle( 'background-color' );\r
+                       dialog.getContentElement( 'picker', 'selectedColor' ).setValue( '' );\r
+                       selected && selected.removeAttribute( 'aria-selected' );\r
+                       selected = null;\r
                }\r
 \r
-               var table = new $el( 'table' );\r
-               createColorTable();\r
+               function updateSelected( evt )\r
+               {\r
+                       var target = evt.data.getTarget(),\r
+                               color;\r
+\r
+                       if ( target.getName() == 'td' &&\r
+                                ( color = target.getChild( 0 ).getHtml() ) )\r
+                       {\r
+                               selected = target;\r
+                               selected.setAttribute( 'aria-selected', true );\r
+                               dialog.getContentElement( 'picker', 'selectedColor' ).setValue( color );\r
+                       }\r
+               }\r
 \r
-               var cellMouseover = function( event )\r
+               // Basing black-white decision off of luma scheme using the Rec. 709 version\r
+               function whiteOrBlack( color )\r
                {\r
-                       var color = new $el( event.data.getTarget() ).getAttribute( 'title' );\r
-                       $doc.getById( 'hicolor' ).setStyle( 'background-color', color );\r
-                       $doc.getById( 'hicolortext' ).setHtml( color );\r
-               };\r
+                       color = color.replace( /^#/, '' );\r
+                       for ( var i = 0, rgb = []; i <= 2; i++ )\r
+                               rgb[i] = parseInt( color.substr( i * 2, 2 ), 16 );\r
+                       var luma = (0.2126 * rgb[0]) + (0.7152 * rgb[1]) + (0.0722 * rgb[2]);\r
+                       return '#' + ( luma >= 165 ? '000' : 'fff' );\r
+               }\r
 \r
-               var cellClick = function( event )\r
+               // Distinguish focused and hover states.\r
+               var focused, hovered;\r
+\r
+               // Apply highlight style.\r
+               function updateHighlight( event )\r
                {\r
-                       var color = new $el( event.data.getTarget() ).getAttribute( 'title' );\r
-                       dialog.getContentElement( 'picker', 'selectedColor' ).setValue( color );\r
-               };\r
+                       // Convert to event.\r
+                       !event.name && ( event = new CKEDITOR.event( event ) );\r
+\r
+                       var isFocus = !(/mouse/).test( event.name ),\r
+                               target = event.data.getTarget(),\r
+                               color;\r
+\r
+                       if ( target.getName() == 'td' && ( color = target.getChild( 0 ).getHtml() ) )\r
+                       {\r
+                               removeHighlight( event );\r
+\r
+                               isFocus ? focused = target : hovered = target;\r
+\r
+                               // Apply outline style to show focus.\r
+                               if ( isFocus )\r
+                               {\r
+                                       target.setStyle( 'border-color', whiteOrBlack( color ) );\r
+                                       target.setStyle( 'border-style', 'dotted' );\r
+                               }\r
+\r
+                               $doc.getById( hicolorId ).setStyle( 'background-color', color );\r
+                               $doc.getById( hicolorTextId ).setHtml( color );\r
+                       }\r
+               }\r
+\r
+               function clearHighlight()\r
+               {\r
+                       var color = focused.getChild( 0 ).getHtml();\r
+                       focused.setStyle( 'border-color', color );\r
+                       focused.setStyle( 'border-style', 'solid' );\r
+                       $doc.getById( hicolorId ).removeStyle( 'background-color' );\r
+                       $doc.getById( hicolorTextId ).setHtml( '&nbsp;' );\r
+                       focused = null;\r
+               }\r
+\r
+               // Remove previously focused style.\r
+               function removeHighlight( event )\r
+               {\r
+                       var isFocus = !(/mouse/).test( event.name ),\r
+                               target = isFocus && focused;\r
+\r
+                       if ( target )\r
+                       {\r
+                               var color = target.getChild( 0 ).getHtml();\r
+                               target.setStyle( 'border-color', color );\r
+                               target.setStyle( 'border-style', 'solid' );\r
+                       }\r
+\r
+                       if ( ! ( focused || hovered ) )\r
+                       {\r
+                               $doc.getById( hicolorId ).removeStyle( 'background-color' );\r
+                               $doc.getById( hicolorTextId ).setHtml( '&nbsp;' );\r
+                       }\r
+               }\r
+\r
+               function onKeyStrokes( evt )\r
+               {\r
+                       var domEvt = evt.data;\r
+\r
+                       var element = domEvt.getTarget();\r
+                       var relative, nodeToMove;\r
+                       var keystroke = domEvt.getKeystroke(),\r
+                               rtl = editor.lang.dir == 'rtl';\r
+\r
+                       switch ( keystroke )\r
+                       {\r
+                               // UP-ARROW\r
+                               case 38 :\r
+                                       // relative is TR\r
+                                       if ( ( relative = element.getParent().getPrevious() ) )\r
+                                       {\r
+                                               nodeToMove = relative.getChild( [ element.getIndex() ] );\r
+                                               nodeToMove.focus();\r
+                                       }\r
+                                       domEvt.preventDefault();\r
+                                       break;\r
+                               // DOWN-ARROW\r
+                               case 40 :\r
+                                       // relative is TR\r
+                                       if ( ( relative = element.getParent().getNext() ) )\r
+                                       {\r
+                                               nodeToMove = relative.getChild( [ element.getIndex() ] );\r
+                                               if ( nodeToMove && nodeToMove.type == 1 )\r
+                                               {\r
+                                                       nodeToMove.focus();\r
+                                               }\r
+                                       }\r
+                                       domEvt.preventDefault();\r
+                                       break;\r
+\r
+                               // SPACE\r
+                               // ENTER\r
+                               case 32 :\r
+                               case 13 :\r
+                                       updateSelected( evt );\r
+                                       domEvt.preventDefault();\r
+                                       break;\r
+\r
+                               // RIGHT-ARROW\r
+                               case rtl ? 37 : 39 :\r
+                                       // relative is TD\r
+                                       if ( ( nodeToMove = element.getNext() ) )\r
+                                       {\r
+                                               if ( nodeToMove.type == 1 )\r
+                                               {\r
+                                                       nodeToMove.focus();\r
+                                                       domEvt.preventDefault( true );\r
+                                               }\r
+                                       }\r
+                                       // relative is TR\r
+                                       else if ( ( relative = element.getParent().getNext() ) )\r
+                                       {\r
+                                               nodeToMove = relative.getChild( [ 0 ] );\r
+                                               if ( nodeToMove && nodeToMove.type == 1 )\r
+                                               {\r
+                                                       nodeToMove.focus();\r
+                                                       domEvt.preventDefault( true );\r
+                                               }\r
+                                       }\r
+                                       break;\r
+\r
+                               // LEFT-ARROW\r
+                               case rtl ? 39 : 37 :\r
+                                       // relative is TD\r
+                                       if ( ( nodeToMove = element.getPrevious() ) )\r
+                                       {\r
+                                               nodeToMove.focus();\r
+                                               domEvt.preventDefault( true );\r
+                                       }\r
+                                       // relative is TR\r
+                                       else if ( ( relative = element.getParent().getPrevious() ) )\r
+                                       {\r
+                                               nodeToMove = relative.getLast();\r
+                                               nodeToMove.focus();\r
+                                               domEvt.preventDefault( true );\r
+                                       }\r
+                                       break;\r
+                               default :\r
+                                       // Do not stop not handled events.\r
+                                       return;\r
+                       }\r
+               }\r
 \r
                function createColorTable()\r
                {\r
+                       table = CKEDITOR.dom.element.createFromHtml\r
+                       (\r
+                               '<table tabIndex="-1" aria-label="' + lang.options + '"' +\r
+                               ' role="grid" style="border-collapse:separate;" cellspacing="0">' +\r
+                               '<caption class="cke_voice_label">' + lang.options + '</caption>' +\r
+                               '<tbody role="presentation"></tbody></table>'\r
+                       );\r
+\r
+                       table.on( 'mouseover', updateHighlight );\r
+                       table.on( 'mouseout', removeHighlight );\r
+\r
                        // Create the base colors array.\r
-                       var aColors = ['00','33','66','99','cc','ff'];\r
+                       var aColors = [ '00', '33', '66', '99', 'cc', 'ff' ];\r
 \r
                        // This function combines two ranges of three values from the color array into a row.\r
                        function appendColorRow( rangeA, rangeB )\r
                        {\r
                                for ( var i = rangeA ; i < rangeA + 3 ; i++ )\r
                                {\r
-                                       var row = table.$.insertRow(-1);\r
+                                       var row = new $el( table.$.insertRow( -1 ) );\r
+                                       row.setAttribute( 'role', 'row' );\r
 \r
                                        for ( var j = rangeB ; j < rangeB + 3 ; j++ )\r
                                        {\r
                                                for ( var n = 0 ; n < 6 ; n++ )\r
                                                {\r
-                                                       appendColorCell( row, '#' + aColors[j] + aColors[n] + aColors[i] );\r
+                                                       appendColorCell( row.$, '#' + aColors[j] + aColors[n] + aColors[i] );\r
                                                }\r
                                        }\r
                                }\r
@@ -65,13 +241,23 @@ CKEDITOR.dialog.add( 'colordialog', function( editor )
                        {\r
                                var cell = new $el( targetRow.insertCell( -1 ) );\r
                                cell.setAttribute( 'class', 'ColorCell' );\r
+                               cell.setAttribute( 'tabIndex', -1 );\r
+                               cell.setAttribute( 'role', 'gridcell' );\r
+\r
+                               cell.on( 'keydown', onKeyStrokes );\r
+                               cell.on( 'click', updateSelected );\r
+                               cell.on( 'focus', updateHighlight );\r
+                               cell.on( 'blur', removeHighlight );\r
+\r
                                cell.setStyle( 'background-color', color );\r
+                               cell.setStyle( 'border', '1px solid ' + color );\r
 \r
-                               cell.setStyle( 'width', '15px' );\r
-                               cell.setStyle( 'height', '15px' );\r
+                               cell.setStyle( 'width', '14px' );\r
+                               cell.setStyle( 'height', '14px' );\r
 \r
-                               // Pass unparsed color value in some markup-degradable form.\r
-                               cell.setAttribute( 'title', color );\r
+                               var colorLabel = numbering( 'color_table_cell' );\r
+                               cell.setAttribute( 'aria-labelledby',colorLabel );\r
+                               cell.append( CKEDITOR.dom.element.createFromHtml( '<span id="' + colorLabel + '" class="cke_voice_label">' + color + '</span>', CKEDITOR.document ) );\r
                        }\r
 \r
                        appendColorRow( 0, 0 );\r
@@ -80,32 +266,32 @@ CKEDITOR.dialog.add( 'colordialog', function( editor )
                        appendColorRow( 3, 3 );\r
 \r
                        // Create the last row.\r
-                       var oRow = table.$.insertRow(-1) ;\r
+                       var oRow = new $el( table.$.insertRow( -1 ) ) ;\r
+                       oRow.setAttribute( 'role', 'row' );\r
 \r
                        // Create the gray scale colors cells.\r
                        for ( var n = 0 ; n < 6 ; n++ )\r
                        {\r
-                               appendColorCell( oRow, '#' + aColors[n] + aColors[n] + aColors[n] ) ;\r
+                               appendColorCell( oRow.$, '#' + aColors[n] + aColors[n] + aColors[n] ) ;\r
                        }\r
 \r
                        // Fill the row with black cells.\r
                        for ( var i = 0 ; i < 12 ; i++ )\r
                        {\r
-                               appendColorCell( oRow, '#000000' ) ;\r
+                               appendColorCell( oRow.$, '#000000' ) ;\r
                        }\r
                }\r
 \r
-               function clear()\r
-               {\r
-                       $doc.getById( 'selhicolor' ).removeStyle( 'background-color' );\r
-                       dialog.getContentElement( 'picker', 'selectedColor' ).setValue( '' );\r
-               }\r
+               var numbering = function( id )\r
+                       {\r
+                               return CKEDITOR.tools.getNextId() + '_' + id;\r
+                       },\r
+                       hicolorId = numbering( 'hicolor' ),\r
+                       hicolorTextId = numbering( 'hicolortext' ),\r
+                       selHiColorId = numbering( 'selhicolor' ),\r
+                       table;\r
 \r
-               var clearActual = $tools.addFunction( function()\r
-               {\r
-                       $doc.getById( 'hicolor' ).removeStyle( 'background-color' );\r
-                       $doc.getById( 'hicolortext' ).setHtml( '&nbsp;' );\r
-               } );\r
+               createColorTable();\r
 \r
                return {\r
                        title : lang.title,\r
@@ -116,6 +302,11 @@ CKEDITOR.dialog.add( 'colordialog', function( editor )
                                // Update reference.\r
                                dialog = this;\r
                        },\r
+                       onHide : function()\r
+                       {\r
+                               clearSelected();\r
+                               clearHighlight();\r
+                       },\r
                        contents : [\r
                                {\r
                                        id : 'picker',\r
@@ -131,15 +322,19 @@ CKEDITOR.dialog.add( 'colordialog', function( editor )
                                                        [\r
                                                                {\r
                                                                        type : 'html',\r
-                                                                       html : '<table onmouseout="CKEDITOR.tools.callFunction( ' + clearActual + ' );">' + table.getHtml() + '</table>',\r
+                                                                       html :  '<div></div>',\r
                                                                        onLoad : function()\r
                                                                        {\r
-                                                                               var table = CKEDITOR.document.getById( this.domId );\r
-                                                                               table.on( 'mouseover', cellMouseover );\r
-                                                                               table.on( 'click', cellClick );\r
+                                                                               CKEDITOR.document.getById( this.domId ).append( table );\r
+                                                                       },\r
+                                                                       focus : function()\r
+                                                                       {\r
+                                                                               // Restore the previously focused cell,\r
+                                                                               // otherwise put the initial focus on the first table cell.\r
+                                                                               ( focused || this.getElement().getElementsByTag( 'td' ).getItem( 0 ) ).focus();\r
                                                                        }\r
                                                                },\r
-                                                               spacer(),\r
+                                                               spacer,\r
                                                                {\r
                                                                        type : 'vbox',\r
                                                                        padding : 0,\r
@@ -149,13 +344,14 @@ CKEDITOR.dialog.add( 'colordialog', function( editor )
                                                                                {\r
                                                                                        type : 'html',\r
                                                                                        html : '<span>' + lang.highlight +'</span>\\r
-                                                                                               <div id="hicolor" style="border: 1px solid; height: 74px; width: 74px;"></div>\\r
-                                                                                               <div id="hicolortext">&nbsp;</div>\\r
-                                                                                               <span>' + lang.selected +'</span>\\r
-                                                                                               <div id="selhicolor" style="border: 1px solid; height: 20px; width: 74px;"></div>'\r
+                                                                                               <div id="' + hicolorId + '" style="border: 1px solid; height: 74px; width: 74px;"></div>\\r
+                                                                                               <div id="' + hicolorTextId + '">&nbsp;</div><span>' + lang.selected + '</span>\\r
+                                                                                               <div id="' + selHiColorId + '" style="border: 1px solid; height: 20px; width: 74px;"></div>'\r
                                                                                },\r
                                                                                {\r
                                                                                        type : 'text',\r
+                                                                                       label : lang.selected,\r
+                                                                                       labelStyle: 'display:none',\r
                                                                                        id : 'selectedColor',\r
                                                                                        style : 'width: 74px',\r
                                                                                        onChange : function()\r
@@ -163,21 +359,21 @@ CKEDITOR.dialog.add( 'colordialog', function( editor )
                                                                                                // Try to update color preview with new value. If fails, then set it no none.\r
                                                                                                try\r
                                                                                                {\r
-                                                                                                       $doc.getById( 'selhicolor' ).setStyle( 'background-color', this.getValue() );\r
+                                                                                                       $doc.getById( selHiColorId ).setStyle( 'background-color', this.getValue() );\r
                                                                                                }\r
                                                                                                catch ( e )\r
                                                                                                {\r
-                                                                                                       clear();\r
+                                                                                                       clearSelected();\r
                                                                                                }\r
                                                                                        }\r
                                                                                },\r
-                                                                               spacer(),\r
+                                                                               spacer,\r
                                                                                {\r
                                                                                        type : 'button',\r
                                                                                        id : 'clear',\r
                                                                                        style : 'margin-top: 5px',\r
                                                                                        label : lang.clear,\r
-                                                                                       onClick : clear\r
+                                                                                       onClick : clearSelected\r
                                                                                }\r
                                                                        ]\r
                                                                }\r