/*\r
-Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.\r
For licensing, see LICENSE.html or http://ckeditor.com/license\r
*/\r
\r
// 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
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
function updateSelected( evt )\r
{\r
- if ( ! ( evt instanceof CKEDITOR.dom.event ) )\r
- evt = new CKEDITOR.dom.event( evt );\r
-\r
- var target = evt.getTarget(),\r
+ var target = evt.data.getTarget(),\r
color;\r
\r
- if ( target.getName() == 'a' && ( color = target.getChild( 0 ).getHtml() ) )\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
+ // Basing black-white decision off of luma scheme using the Rec. 709 version\r
+ function whiteOrBlack( 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
+ // Distinguish focused and hover states.\r
+ var focused, hovered;\r
+\r
+ // Apply highlight style.\r
function updateHighlight( event )\r
{\r
- if ( ! ( event instanceof CKEDITOR.dom.event ) )\r
- event = event.data;\r
+ // Convert to event.\r
+ !event.name && ( event = new CKEDITOR.event( event ) );\r
\r
- var target = event.getTarget(),\r
- color;\r
+ var isFocus = !(/mouse/).test( event.name ),\r
+ target = event.data.getTarget(),\r
+ color;\r
\r
- if ( target.getName() == 'a' && ( color = target.getChild( 0 ).getHtml() ) )\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
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( ' ' );\r
+ focused = null;\r
}\r
\r
- var onMouseout = $tools.addFunction( clearHighlight ),\r
- onClick = updateSelected,\r
- onClickHandler = CKEDITOR.tools.addFunction( onClick ),\r
- onFocus = updateHighlight,\r
- onBlur = clearHighlight;\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( ' ' );\r
+ }\r
+ }\r
\r
- var onKeydownHandler = CKEDITOR.tools.addFunction( function( ev )\r
+ function onKeyStrokes( evt )\r
{\r
- ev = new CKEDITOR.dom.event( ev );\r
- var element = ev.getTarget();\r
+ var domEvt = evt.data;\r
+\r
+ var element = domEvt.getTarget();\r
var relative, nodeToMove;\r
- var keystroke = ev.getKeystroke(),\r
+ var keystroke = domEvt.getKeystroke(),\r
rtl = editor.lang.dir == 'rtl';\r
\r
switch ( keystroke )\r
// UP-ARROW\r
case 38 :\r
// relative is TR\r
- if ( ( relative = element.getParent().getParent().getPrevious() ) )\r
+ if ( ( relative = element.getParent().getPrevious() ) )\r
{\r
- nodeToMove = relative.getChild( [element.getParent().getIndex(), 0] );\r
+ nodeToMove = relative.getChild( [ element.getIndex() ] );\r
nodeToMove.focus();\r
- onBlur( ev, element );\r
- onFocus( ev, nodeToMove );\r
}\r
- ev.preventDefault();\r
+ domEvt.preventDefault();\r
break;\r
// DOWN-ARROW\r
case 40 :\r
// relative is TR\r
- if ( ( relative = element.getParent().getParent().getNext() ) )\r
+ if ( ( relative = element.getParent().getNext() ) )\r
{\r
- nodeToMove = relative.getChild( [ element.getParent().getIndex(), 0 ] );\r
+ nodeToMove = relative.getChild( [ element.getIndex() ] );\r
if ( nodeToMove && nodeToMove.type == 1 )\r
{\r
nodeToMove.focus();\r
- onBlur( ev, element );\r
- onFocus( ev, nodeToMove );\r
}\r
}\r
- ev.preventDefault();\r
+ domEvt.preventDefault();\r
break;\r
+\r
// SPACE\r
- // ENTER is already handled as onClick\r
+ // ENTER\r
case 32 :\r
- onClick( ev );\r
- ev.preventDefault();\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 ( ( relative = element.getParent().getNext() ) )\r
+ if ( ( nodeToMove = element.getNext() ) )\r
{\r
- nodeToMove = relative.getChild( 0 );\r
if ( nodeToMove.type == 1 )\r
{\r
nodeToMove.focus();\r
- onBlur( ev, element );\r
- onFocus( ev, nodeToMove );\r
- ev.preventDefault( true );\r
+ domEvt.preventDefault( true );\r
}\r
- else\r
- onBlur( null, element );\r
}\r
// relative is TR\r
- else if ( ( relative = element.getParent().getParent().getNext() ) )\r
+ else if ( ( relative = element.getParent().getNext() ) )\r
{\r
- nodeToMove = relative.getChild( [ 0, 0 ] );\r
+ nodeToMove = relative.getChild( [ 0 ] );\r
if ( nodeToMove && nodeToMove.type == 1 )\r
{\r
nodeToMove.focus();\r
- onBlur( ev, element );\r
- onFocus( ev, nodeToMove );\r
- ev.preventDefault( true );\r
+ domEvt.preventDefault( true );\r
}\r
- else\r
- onBlur( null, element );\r
}\r
break;\r
\r
// LEFT-ARROW\r
case rtl ? 39 : 37 :\r
// relative is TD\r
- if ( ( relative = element.getParent().getPrevious() ) )\r
+ if ( ( nodeToMove = element.getPrevious() ) )\r
{\r
- nodeToMove = relative.getChild( 0 );\r
nodeToMove.focus();\r
- onBlur( ev, element );\r
- onFocus( ev, nodeToMove );\r
- ev.preventDefault( true );\r
+ domEvt.preventDefault( true );\r
}\r
// relative is TR\r
- else if ( ( relative = element.getParent().getParent().getPrevious() ) )\r
+ else if ( ( relative = element.getParent().getPrevious() ) )\r
{\r
- nodeToMove = relative.getLast().getChild( 0 );\r
+ nodeToMove = relative.getLast();\r
nodeToMove.focus();\r
- onBlur( ev, element );\r
- onFocus( ev, nodeToMove );\r
- ev.preventDefault( true );\r
+ domEvt.preventDefault( true );\r
}\r
- else\r
- onBlur( null, element );\r
break;\r
default :\r
// Do not stop not handled events.\r
return;\r
}\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
\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
{\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
-\r
- var index = cell.$.cellIndex + 1 + 18 * targetRow.rowIndex;\r
- cell.append( CKEDITOR.dom.element.createFromHtml(\r
- '<a href="javascript: void(0);" role="option"' +\r
- ' aria-posinset="' + index + '"' +\r
- ' aria-setsize="' + 13 * 18 + '"' +\r
- ' style="cursor: pointer;display:block;width:100%;height:100% " title="'+ CKEDITOR.tools.htmlEncode( color )+ '"' +\r
- ' onkeydown="CKEDITOR.tools.callFunction( ' + onKeydownHandler + ', event, this )"' +\r
- ' onclick="CKEDITOR.tools.callFunction(' + onClickHandler + ', event, this ); return false;"' +\r
- ' tabindex="-1"><span class="cke_voice_label">' + color + '</span> </a>', CKEDITOR.document ) );\r
+ cell.setStyle( 'width', '14px' );\r
+ cell.setStyle( 'height', '14px' );\r
+\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
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
- var table = new $el( 'table' );\r
- createColorTable();\r
-\r
var numbering = function( id )\r
{\r
return CKEDITOR.tools.getNextId() + '_' + id;\r
hicolorId = numbering( 'hicolor' ),\r
hicolorTextId = numbering( 'hicolortext' ),\r
selHiColorId = numbering( 'selhicolor' ),\r
- tableLabelId = numbering( 'color_table_label' );\r
+ table;\r
+\r
+ createColorTable();\r
\r
return {\r
title : lang.title,\r
// Update reference.\r
dialog = this;\r
},\r
+ onHide : function()\r
+ {\r
+ clearSelected();\r
+ clearHighlight();\r
+ },\r
contents : [\r
{\r
id : 'picker',\r
[\r
{\r
type : 'html',\r
- html : '<table role="listbox" aria-labelledby="' + tableLabelId + '" onmouseout="CKEDITOR.tools.callFunction( ' + onMouseout + ' );">' + table.getHtml() + '</table>' +\r
- '<span id="' + tableLabelId + '" class="cke_voice_label">' + lang.options +'</span>',\r
+ html : '<div></div>',\r
onLoad : function()\r
{\r
- var table = CKEDITOR.document.getById( this.domId );\r
- table.on( 'mouseover', updateHighlight );\r
+ CKEDITOR.document.getById( this.domId ).append( table );\r
},\r
- focus: function()\r
+ focus : function()\r
{\r
- var firstColor = this.getElement().getElementsByTag( 'a' ).getItem( 0 );\r
- firstColor.focus();\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