]> git.immae.eu Git - perso/Immae/Projets/packagist/connexionswing-ckeditor-component.git/blob - sources/plugins/elementspath/plugin.js
Initial commit
[perso/Immae/Projets/packagist/connexionswing-ckeditor-component.git] / sources / plugins / elementspath / plugin.js
1 /**
2 * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md 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 var commands = {
13 toolbarFocus: {
14 editorFocus: false,
15 readOnly: 1,
16 exec: function( editor ) {
17 var idBase = editor._.elementsPath.idBase;
18 var element = CKEDITOR.document.getById( idBase + '0' );
19
20 // Make the first button focus accessible for IE. (#3417)
21 // Adobe AIR instead need while of delay.
22 element && element.focus( CKEDITOR.env.ie || CKEDITOR.env.air );
23 }
24 }
25 };
26
27 var emptyHtml = '<span class="cke_path_empty">&nbsp;</span>';
28
29 var extra = '';
30
31 // Some browsers don't cancel key events in the keydown but in the
32 // keypress.
33 // TODO: Check if really needed.
34 if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )
35 extra += ' onkeypress="return false;"';
36
37 // With Firefox, we need to force the button to redraw, otherwise it
38 // will remain in the focus state.
39 if ( CKEDITOR.env.gecko )
40 extra += ' onblur="this.style.cssText = this.style.cssText;"';
41
42 var pathItemTpl = CKEDITOR.addTemplate( 'pathItem', '<a' +
43 ' id="{id}"' +
44 ' href="{jsTitle}"' +
45 ' tabindex="-1"' +
46 ' class="cke_path_item"' +
47 ' title="{label}"' +
48 extra +
49 ' hidefocus="true" ' +
50 ' onkeydown="return CKEDITOR.tools.callFunction({keyDownFn},{index}, event );"' +
51 ' onclick="CKEDITOR.tools.callFunction({clickFn},{index}); return false;"' +
52 ' role="button" aria-label="{label}">' +
53 '{text}' +
54 '</a>' );
55
56 CKEDITOR.plugins.add( 'elementspath', {
57 // jscs:disable maximumLineLength
58 lang: 'af,ar,bg,bn,bs,ca,cs,cy,da,de,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
59 // jscs:enable maximumLineLength
60 init: function( editor ) {
61 editor._.elementsPath = {
62 idBase: 'cke_elementspath_' + CKEDITOR.tools.getNextNumber() + '_',
63 filters: []
64 };
65
66 editor.on( 'uiSpace', function( event ) {
67 if ( event.data.space == 'bottom' )
68 initElementsPath( editor, event.data );
69 } );
70 }
71 } );
72
73 function initElementsPath( editor, bottomSpaceData ) {
74 var spaceId = editor.ui.spaceId( 'path' ),
75 spaceElement,
76 getSpaceElement = function() {
77 if ( !spaceElement )
78 spaceElement = CKEDITOR.document.getById( spaceId );
79 return spaceElement;
80 },
81 elementsPath = editor._.elementsPath,
82 idBase = elementsPath.idBase;
83
84 bottomSpaceData.html += '<span id="' + spaceId + '_label" class="cke_voice_label">' + editor.lang.elementspath.eleLabel + '</span>' +
85 '<span id="' + spaceId + '" class="cke_path" role="group" aria-labelledby="' + spaceId + '_label">' + emptyHtml + '</span>';
86
87 // Register the ui element to the focus manager.
88 editor.on( 'uiReady', function() {
89 var element = editor.ui.space( 'path' );
90 element && editor.focusManager.add( element, 1 );
91 } );
92
93 function onClick( elementIndex ) {
94 var element = elementsPath.list[ elementIndex ];
95 if ( element.equals( editor.editable() ) || element.getAttribute( 'contenteditable' ) == 'true' ) {
96 var range = editor.createRange();
97 range.selectNodeContents( element );
98 range.select();
99 } else {
100 editor.getSelection().selectElement( element );
101 }
102
103 // It is important to focus() *after* the above selection
104 // manipulation, otherwise Firefox will have troubles. #10119
105 editor.focus();
106 }
107
108 elementsPath.onClick = onClick;
109
110 var onClickHanlder = CKEDITOR.tools.addFunction( onClick ),
111 onKeyDownHandler = CKEDITOR.tools.addFunction( function( elementIndex, ev ) {
112 var idBase = elementsPath.idBase,
113 element;
114
115 ev = new CKEDITOR.dom.event( ev );
116
117 var rtl = editor.lang.dir == 'rtl';
118 switch ( ev.getKeystroke() ) {
119 case rtl ? 39 : 37: // LEFT-ARROW
120 case 9: // TAB
121 element = CKEDITOR.document.getById( idBase + ( elementIndex + 1 ) );
122 if ( !element )
123 element = CKEDITOR.document.getById( idBase + '0' );
124 element.focus();
125 return false;
126
127 case rtl ? 37 : 39: // RIGHT-ARROW
128 case CKEDITOR.SHIFT + 9: // SHIFT + TAB
129 element = CKEDITOR.document.getById( idBase + ( elementIndex - 1 ) );
130 if ( !element )
131 element = CKEDITOR.document.getById( idBase + ( elementsPath.list.length - 1 ) );
132 element.focus();
133 return false;
134
135 case 27: // ESC
136 editor.focus();
137 return false;
138
139 case 13: // ENTER // Opera
140 case 32: // SPACE
141 onClick( elementIndex );
142 return false;
143 }
144 return true;
145 } );
146
147 editor.on( 'selectionChange', function() {
148 var html = [],
149 elementsList = elementsPath.list = [],
150 namesList = [],
151 filters = elementsPath.filters,
152 isContentEditable = true,
153
154 // Use elementPath to consider children of editable only (#11124).
155 elementsChain = editor.elementPath().elements,
156 name;
157
158 // Starts iteration from body element, skipping html.
159 for ( var j = elementsChain.length; j--; ) {
160 var element = elementsChain[ j ],
161 ignore = 0;
162
163 if ( element.data( 'cke-display-name' ) )
164 name = element.data( 'cke-display-name' );
165 else if ( element.data( 'cke-real-element-type' ) )
166 name = element.data( 'cke-real-element-type' );
167 else
168 name = element.getName();
169
170 isContentEditable = element.hasAttribute( 'contenteditable' ) ?
171 element.getAttribute( 'contenteditable' ) == 'true' : isContentEditable;
172
173 // If elem is non-contenteditable, and it's not specifying contenteditable
174 // attribute - then elem should be ignored.
175 if ( !isContentEditable && !element.hasAttribute( 'contenteditable' ) )
176 ignore = 1;
177
178 for ( var i = 0; i < filters.length; i++ ) {
179 var ret = filters[ i ]( element, name );
180 if ( ret === false ) {
181 ignore = 1;
182 break;
183 }
184 name = ret || name;
185 }
186
187 if ( !ignore ) {
188 elementsList.unshift( element );
189 namesList.unshift( name );
190 }
191 }
192
193 for ( var iterationLimit = elementsList.length, index = 0; index < iterationLimit; index++ ) {
194 name = namesList[ index ];
195 var label = editor.lang.elementspath.eleTitle.replace( /%1/, name ),
196 item = pathItemTpl.output( {
197 id: idBase + index,
198 label: label,
199 text: name,
200 jsTitle: 'javascript:void(\'' + name + '\')', // jshint ignore:line
201 index: index,
202 keyDownFn: onKeyDownHandler,
203 clickFn: onClickHanlder
204 } );
205
206 html.unshift( item );
207 }
208
209 var space = getSpaceElement();
210 space.setHtml( html.join( '' ) + emptyHtml );
211 editor.fire( 'elementsPathUpdate', { space: space } );
212 } );
213
214 function empty() {
215 spaceElement && spaceElement.setHtml( emptyHtml );
216 delete elementsPath.list;
217 }
218
219 editor.on( 'readOnly', empty );
220 editor.on( 'contentDomUnload', empty );
221
222 editor.addCommand( 'elementsPathFocus', commands.toolbarFocus );
223 editor.setKeystroke( CKEDITOR.ALT + 122 /*F11*/, 'elementsPathFocus' );
224 }
225 } )();
226
227 /**
228 * Fired when the contents of the elementsPath are changed.
229 *
230 * @event elementsPathUpdate
231 * @member CKEDITOR.editor
232 * @param {CKEDITOR.editor} editor This editor instance.
233 * @param data
234 * @param {CKEDITOR.dom.element} data.space The elementsPath container.
235 */