      1 ﻿/*
      2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
      3 For licensing, see LICENSE.html or http://ckeditor.com/license
      4 */
      5
      6 /**
      7  * @fileOverview The "elementspath" plugin. It shows all elements in the DOM
      8  *		parent tree relative to the current selection in the editing area.
      9  */
     10
     11 (function()
     12 {
     13 	var commands =
     14 	{
     15 		toolbarFocus :
     16 		{
     17 			exec : function( editor )
     18 			{
     19 				var idBase = editor._.elementsPath.idBase;
     20 				var element = CKEDITOR.document.getById( idBase + '0' );
     21
     22 				if ( element )
     23 					element.focus();
     24 			}
     25 		}
     26 	};
     27
     28 	var emptyHtml = '<span class="cke_empty"> </span>';
     29
     30 	CKEDITOR.plugins.add( 'elementspath',
     31 	{
     32 		requires : [ 'selection' ],
     33
     34 		init : function( editor )
     35 		{
     36 			var spaceId = 'cke_path_' + editor.name;
     37 			var spaceElement;
     38 			var getSpaceElement = function()
     39 			{
     40 				if ( !spaceElement )
     41 					spaceElement = CKEDITOR.document.getById( spaceId );
     42 				return spaceElement;
     43 			};
     44
     45 			var idBase = 'cke_elementspath_' + CKEDITOR.tools.getNextNumber() + '_';
     46
     47 			editor._.elementsPath = { idBase : idBase };
     48
     49 			editor.on( 'themeSpace', function( event )
     50 				{
     51 					if ( event.data.space == 'bottom' )
     52 						event.data.html += '<div id="' + spaceId + '" class="cke_path">' + emptyHtml + '</div>';
     53 				});
     54
     55 			editor.on( 'selectionChange', function( ev )
     56 				{
     57 					var env = CKEDITOR.env;
     58
     59 					var selection = ev.data.selection;
     60
     61 					var element = selection.getStartElement(),
     62 						html = [],
     63 						elementsList = this._.elementsPath.list = [];
     64
     65 					while ( element )
     66 					{
     67 						var index = elementsList.push( element ) - 1;
     68 						var name;
     69 						if ( element.getAttribute( '_cke_real_element_type' ) )
     70 							name = element.getAttribute( '_cke_real_element_type' );
     71 						else
     72 							name = element.getName();
     73
     74 						// Use this variable to add conditional stuff to the
     75 						// HTML (because we are doing it in reverse order... unshift).
     76 						var extra = '';
     77
     78 						// Some browsers don't cancel key events in the keydown but in the
     79 						// keypress.
     80 						// TODO: Check if really needed for Gecko+Mac.
     81 						if ( env.opera || ( env.gecko && env.mac ) )
     82 							extra += ' onkeypress="return false;"';
     83
     84 						// With Firefox, we need to force the button to redraw, otherwise it
     85 						// will remain in the focus state.
     86 						if ( env.gecko )
     87 							extra += ' onblur="this.style.cssText = this.style.cssText;"';
     88
     89 						html.unshift(
     90 							'<a' +
     91 								' id="', idBase, index, '"' +
     92 								' href="javascript:void(\'', name, '\')"' +
     93 								' tabindex="-1"' +
     94 								' title="', editor.lang.elementsPath.eleTitle.replace( /%1/, name ), '"' +
     95 								( ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 ) ?
     96 								' onfocus="event.preventBubble();"' : '' ) +
     97 								' hidefocus="true" ' +
     98 								' onkeydown="return CKEDITOR._.elementsPath.keydown(\'', this.name, '\',', index, ', event);"' +
     99 								extra ,
    100 								' onclick="return CKEDITOR._.elementsPath.click(\'', this.name, '\',', index, ');">',
    101 									name,
    102 							'</a>' );
    103
    104 						if ( name == 'body' )
    105 							break;
    106
    107 						element = element.getParent();
    108 					}
    109
    110 					getSpaceElement().setHtml( html.join('') + emptyHtml );
    111 				});
    112
    113 			editor.on( 'contentDomUnload', function()
    114 				{
    115 					getSpaceElement().setHtml( emptyHtml );
    116 				});
    117
    118 			editor.addCommand( 'elementsPathFocus', commands.toolbarFocus );
    119 		}
    120 	});
    121 })();
    122
    123 /**
    124  * Handles the click on an element in the element path.
    125  * @private
    126  */
    127 CKEDITOR._.elementsPath =
    128 {
    129 	click : function( instanceName, elementIndex )
    130 	{
    131 		var editor = CKEDITOR.instances[ instanceName ];
    132 		editor.focus();
    133
    134 		var element = editor._.elementsPath.list[ elementIndex ];
    135 		editor.getSelection().selectElement( element );
    136
    137 		return false;
    138 	},
    139
    140 	keydown : function( instanceName, elementIndex, ev )
    141 	{
    142 		var instance = CKEDITOR.ui.button._.instances[ elementIndex ];
    143 		var editor = CKEDITOR.instances[ instanceName ];
    144 		var idBase = editor._.elementsPath.idBase;
    145
    146 		var element;
    147
    148 		ev = new CKEDITOR.dom.event( ev );
    149
    150 		switch ( ev.getKeystroke() )
    151 		{
    152 			case 37 :					// LEFT-ARROW
    153 			case 9 :					// TAB
    154 				element = CKEDITOR.document.getById( idBase + ( elementIndex + 1 ) );
    155 				if ( !element )
    156 					element = CKEDITOR.document.getById( idBase + '0' );
    157 				element.focus();
    158 				return false;
    159
    160 			case 39 :					// RIGHT-ARROW
    161 			case CKEDITOR.SHIFT + 9 :	// SHIFT + TAB
    162 				element = CKEDITOR.document.getById( idBase + ( elementIndex - 1 ) );
    163 				if ( !element )
    164 					element = CKEDITOR.document.getById( idBase + ( editor._.elementsPath.list.length - 1 ) );
    165 				element.focus();
    166 				return false;
    167
    168 			case 27 :					// ESC
    169 				editor.focus();
    170 				return false;
    171
    172 			case 13 :					// ENTER	// Opera
    173 			case 32 :					// SPACE
    174 				this.click( instanceName, elementIndex );
    175 				return false;
    176
    177 			//default :
    178 			//	alert( ev.getKeystroke() );
    179 		}
    180 		return true;
    181 	}
    182 };
    183