diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2017-01-20 00:55:51 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2017-01-20 00:55:51 +0100 |
commit | c63493c899de714b05b0521bb38aab60d19030ef (patch) | |
tree | fcb2b261afa0f3c2bd6b48929b64724c71192bae /sources/plugins/floatpanel | |
download | ludivine-ckeditor-component-c63493c899de714b05b0521bb38aab60d19030ef.tar.gz ludivine-ckeditor-component-c63493c899de714b05b0521bb38aab60d19030ef.tar.zst ludivine-ckeditor-component-c63493c899de714b05b0521bb38aab60d19030ef.zip |
Validation initiale4.6.2.1
Diffstat (limited to 'sources/plugins/floatpanel')
-rw-r--r-- | sources/plugins/floatpanel/plugin.js | 598 |
1 files changed, 598 insertions, 0 deletions
diff --git a/sources/plugins/floatpanel/plugin.js b/sources/plugins/floatpanel/plugin.js new file mode 100644 index 0000000..1a851f9 --- /dev/null +++ b/sources/plugins/floatpanel/plugin.js | |||
@@ -0,0 +1,598 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | CKEDITOR.plugins.add( 'floatpanel', { | ||
7 | requires: 'panel' | ||
8 | } ); | ||
9 | |||
10 | ( function() { | ||
11 | var panels = {}; | ||
12 | |||
13 | function getPanel( editor, doc, parentElement, definition, level ) { | ||
14 | // Generates the panel key: docId-eleId-skinName-langDir[-uiColor][-CSSs][-level] | ||
15 | var key = CKEDITOR.tools.genKey( doc.getUniqueId(), parentElement.getUniqueId(), editor.lang.dir, editor.uiColor || '', definition.css || '', level || '' ), | ||
16 | panel = panels[ key ]; | ||
17 | |||
18 | if ( !panel ) { | ||
19 | panel = panels[ key ] = new CKEDITOR.ui.panel( doc, definition ); | ||
20 | panel.element = parentElement.append( CKEDITOR.dom.element.createFromHtml( panel.render( editor ), doc ) ); | ||
21 | |||
22 | panel.element.setStyles( { | ||
23 | display: 'none', | ||
24 | position: 'absolute' | ||
25 | } ); | ||
26 | } | ||
27 | |||
28 | return panel; | ||
29 | } | ||
30 | |||
31 | /** | ||
32 | * Represents a floating panel UI element. | ||
33 | * | ||
34 | * It is reused by rich combos, color combos, menus, etc. | ||
35 | * and it renders its content using {@link CKEDITOR.ui.panel}. | ||
36 | * | ||
37 | * @class | ||
38 | * @todo | ||
39 | */ | ||
40 | CKEDITOR.ui.floatPanel = CKEDITOR.tools.createClass( { | ||
41 | /** | ||
42 | * Creates a floatPanel class instance. | ||
43 | * | ||
44 | * @constructor | ||
45 | * @param {CKEDITOR.editor} editor | ||
46 | * @param {CKEDITOR.dom.element} parentElement | ||
47 | * @param {Object} definition Definition of the panel that will be floating. | ||
48 | * @param {Number} level | ||
49 | */ | ||
50 | $: function( editor, parentElement, definition, level ) { | ||
51 | definition.forceIFrame = 1; | ||
52 | |||
53 | // In case of editor with floating toolbar append panels that should float | ||
54 | // to the main UI element. | ||
55 | if ( definition.toolbarRelated && editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ) | ||
56 | parentElement = CKEDITOR.document.getById( 'cke_' + editor.name ); | ||
57 | |||
58 | var doc = parentElement.getDocument(), | ||
59 | panel = getPanel( editor, doc, parentElement, definition, level || 0 ), | ||
60 | element = panel.element, | ||
61 | iframe = element.getFirst(), | ||
62 | that = this; | ||
63 | |||
64 | // Disable native browser menu. (#4825) | ||
65 | element.disableContextMenu(); | ||
66 | |||
67 | this.element = element; | ||
68 | |||
69 | this._ = { | ||
70 | editor: editor, | ||
71 | // The panel that will be floating. | ||
72 | panel: panel, | ||
73 | parentElement: parentElement, | ||
74 | definition: definition, | ||
75 | document: doc, | ||
76 | iframe: iframe, | ||
77 | children: [], | ||
78 | dir: editor.lang.dir, | ||
79 | showBlockParams: null | ||
80 | }; | ||
81 | |||
82 | editor.on( 'mode', hide ); | ||
83 | editor.on( 'resize', hide ); | ||
84 | |||
85 | // When resize of the window is triggered floatpanel should be repositioned according to new dimensions. | ||
86 | // #11724. Fixes issue with undesired panel hiding on Android and iOS. | ||
87 | doc.getWindow().on( 'resize', function() { | ||
88 | this.reposition(); | ||
89 | }, this ); | ||
90 | |||
91 | // We need a wrapper because events implementation doesn't allow to attach | ||
92 | // one listener more than once for the same event on the same object. | ||
93 | // Remember that floatPanel#hide is shared between all instances. | ||
94 | function hide() { | ||
95 | that.hide(); | ||
96 | } | ||
97 | }, | ||
98 | |||
99 | proto: { | ||
100 | /** | ||
101 | * @todo | ||
102 | */ | ||
103 | addBlock: function( name, block ) { | ||
104 | return this._.panel.addBlock( name, block ); | ||
105 | }, | ||
106 | |||
107 | /** | ||
108 | * @todo | ||
109 | */ | ||
110 | addListBlock: function( name, multiSelect ) { | ||
111 | return this._.panel.addListBlock( name, multiSelect ); | ||
112 | }, | ||
113 | |||
114 | /** | ||
115 | * @todo | ||
116 | */ | ||
117 | getBlock: function( name ) { | ||
118 | return this._.panel.getBlock( name ); | ||
119 | }, | ||
120 | |||
121 | /** | ||
122 | * Shows the panel block. | ||
123 | * | ||
124 | * @param {String} name | ||
125 | * @param {CKEDITOR.dom.element} offsetParent Positioned parent. | ||
126 | * @param {Number} corner | ||
127 | * | ||
128 | * * For LTR (left to right) oriented editor: | ||
129 | * * `1` = top-left | ||
130 | * * `2` = top-right | ||
131 | * * `3` = bottom-right | ||
132 | * * `4` = bottom-left | ||
133 | * * For RTL (right to left): | ||
134 | * * `1` = top-right | ||
135 | * * `2` = top-left | ||
136 | * * `3` = bottom-left | ||
137 | * * `4` = bottom-right | ||
138 | * | ||
139 | * @param {Number} [offsetX=0] | ||
140 | * @param {Number} [offsetY=0] | ||
141 | * @param {Function} [callback] A callback function executed when block positioning is done. | ||
142 | * @todo what do exactly these params mean (especially corner)? | ||
143 | */ | ||
144 | showBlock: function( name, offsetParent, corner, offsetX, offsetY, callback ) { | ||
145 | var panel = this._.panel, | ||
146 | block = panel.showBlock( name ); | ||
147 | |||
148 | this._.showBlockParams = [].slice.call( arguments ); | ||
149 | this.allowBlur( false ); | ||
150 | |||
151 | // Record from where the focus is when open panel. | ||
152 | var editable = this._.editor.editable(); | ||
153 | this._.returnFocus = editable.hasFocus ? editable : new CKEDITOR.dom.element( CKEDITOR.document.$.activeElement ); | ||
154 | this._.hideTimeout = 0; | ||
155 | |||
156 | var element = this.element, | ||
157 | iframe = this._.iframe, | ||
158 | // Edge prefers iframe's window to the iframe, just like the rest of the browsers (#13143). | ||
159 | focused = CKEDITOR.env.ie && !CKEDITOR.env.edge ? iframe : new CKEDITOR.dom.window( iframe.$.contentWindow ), | ||
160 | doc = element.getDocument(), | ||
161 | positionedAncestor = this._.parentElement.getPositionedAncestor(), | ||
162 | position = offsetParent.getDocumentPosition( doc ), | ||
163 | positionedAncestorPosition = positionedAncestor ? positionedAncestor.getDocumentPosition( doc ) : { x: 0, y: 0 }, | ||
164 | rtl = this._.dir == 'rtl', | ||
165 | left = position.x + ( offsetX || 0 ) - positionedAncestorPosition.x, | ||
166 | top = position.y + ( offsetY || 0 ) - positionedAncestorPosition.y; | ||
167 | |||
168 | // Floating panels are off by (-1px, 0px) in RTL mode. (#3438) | ||
169 | if ( rtl && ( corner == 1 || corner == 4 ) ) | ||
170 | left += offsetParent.$.offsetWidth; | ||
171 | else if ( !rtl && ( corner == 2 || corner == 3 ) ) | ||
172 | left += offsetParent.$.offsetWidth - 1; | ||
173 | |||
174 | if ( corner == 3 || corner == 4 ) | ||
175 | top += offsetParent.$.offsetHeight - 1; | ||
176 | |||
177 | // Memorize offsetParent by it's ID. | ||
178 | this._.panel._.offsetParentId = offsetParent.getId(); | ||
179 | |||
180 | element.setStyles( { | ||
181 | top: top + 'px', | ||
182 | left: 0, | ||
183 | display: '' | ||
184 | } ); | ||
185 | |||
186 | // Don't use display or visibility style because we need to | ||
187 | // calculate the rendering layout later and focus the element. | ||
188 | element.setOpacity( 0 ); | ||
189 | |||
190 | // To allow the context menu to decrease back their width | ||
191 | element.getFirst().removeStyle( 'width' ); | ||
192 | |||
193 | // Report to focus manager. | ||
194 | this._.editor.focusManager.add( focused ); | ||
195 | |||
196 | // Configure the IFrame blur event. Do that only once. | ||
197 | if ( !this._.blurSet ) { | ||
198 | |||
199 | // With addEventListener compatible browsers, we must | ||
200 | // useCapture when registering the focus/blur events to | ||
201 | // guarantee they will be firing in all situations. (#3068, #3222 ) | ||
202 | CKEDITOR.event.useCapture = true; | ||
203 | |||
204 | focused.on( 'blur', function( ev ) { | ||
205 | // As we are using capture to register the listener, | ||
206 | // the blur event may get fired even when focusing | ||
207 | // inside the window itself, so we must ensure the | ||
208 | // target is out of it. | ||
209 | if ( !this.allowBlur() || ev.data.getPhase() != CKEDITOR.EVENT_PHASE_AT_TARGET ) | ||
210 | return; | ||
211 | |||
212 | if ( this.visible && !this._.activeChild ) { | ||
213 | // [iOS] Allow hide to be prevented if touch is bound | ||
214 | // to any parent of the iframe blur happens before touch (#10714). | ||
215 | if ( CKEDITOR.env.iOS ) { | ||
216 | if ( !this._.hideTimeout ) | ||
217 | this._.hideTimeout = CKEDITOR.tools.setTimeout( doHide, 0, this ); | ||
218 | } else { | ||
219 | doHide.call( this ); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | function doHide() { | ||
224 | // Panel close is caused by user's navigating away the focus, e.g. click outside the panel. | ||
225 | // DO NOT restore focus in this case. | ||
226 | delete this._.returnFocus; | ||
227 | this.hide(); | ||
228 | } | ||
229 | }, this ); | ||
230 | |||
231 | focused.on( 'focus', function() { | ||
232 | this._.focused = true; | ||
233 | this.hideChild(); | ||
234 | this.allowBlur( true ); | ||
235 | }, this ); | ||
236 | |||
237 | // [iOS] if touch is bound to any parent of the iframe blur | ||
238 | // happens twice before touchstart and before touchend (#10714). | ||
239 | if ( CKEDITOR.env.iOS ) { | ||
240 | // Prevent false hiding on blur. | ||
241 | // We don't need to return focus here because touchend will fire anyway. | ||
242 | // If user scrolls and pointer gets out of the panel area touchend will also fire. | ||
243 | focused.on( 'touchstart', function() { | ||
244 | clearTimeout( this._.hideTimeout ); | ||
245 | }, this ); | ||
246 | |||
247 | // Set focus back to handle blur and hide panel when needed. | ||
248 | focused.on( 'touchend', function() { | ||
249 | this._.hideTimeout = 0; | ||
250 | this.focus(); | ||
251 | }, this ); | ||
252 | } | ||
253 | |||
254 | CKEDITOR.event.useCapture = false; | ||
255 | |||
256 | this._.blurSet = 1; | ||
257 | } | ||
258 | |||
259 | panel.onEscape = CKEDITOR.tools.bind( function( keystroke ) { | ||
260 | if ( this.onEscape && this.onEscape( keystroke ) === false ) | ||
261 | return false; | ||
262 | }, this ); | ||
263 | |||
264 | CKEDITOR.tools.setTimeout( function() { | ||
265 | var panelLoad = CKEDITOR.tools.bind( function() { | ||
266 | var target = element; | ||
267 | |||
268 | // Reset panel width as the new content can be narrower | ||
269 | // than the old one. (#9355) | ||
270 | target.removeStyle( 'width' ); | ||
271 | |||
272 | if ( block.autoSize ) { | ||
273 | var panelDoc = block.element.getDocument(), | ||
274 | width = ( ( CKEDITOR.env.webkit || CKEDITOR.env.edge ) ? block.element : panelDoc.getBody() ).$.scrollWidth; | ||
275 | |||
276 | // Account for extra height needed due to IE quirks box model bug: | ||
277 | // http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug | ||
278 | // (#3426) | ||
279 | if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && width > 0 ) | ||
280 | width += ( target.$.offsetWidth || 0 ) - ( target.$.clientWidth || 0 ) + 3; | ||
281 | |||
282 | // Add some extra pixels to improve the appearance. | ||
283 | width += 10; | ||
284 | |||
285 | target.setStyle( 'width', width + 'px' ); | ||
286 | |||
287 | var height = block.element.$.scrollHeight; | ||
288 | |||
289 | // Account for extra height needed due to IE quirks box model bug: | ||
290 | // http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug | ||
291 | // (#3426) | ||
292 | if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && height > 0 ) | ||
293 | height += ( target.$.offsetHeight || 0 ) - ( target.$.clientHeight || 0 ) + 3; | ||
294 | |||
295 | target.setStyle( 'height', height + 'px' ); | ||
296 | |||
297 | // Fix IE < 8 visibility. | ||
298 | panel._.currentBlock.element.setStyle( 'display', 'none' ).removeStyle( 'display' ); | ||
299 | } else { | ||
300 | target.removeStyle( 'height' ); | ||
301 | } | ||
302 | |||
303 | // Flip panel layout horizontally in RTL with known width. | ||
304 | if ( rtl ) | ||
305 | left -= element.$.offsetWidth; | ||
306 | |||
307 | // Pop the style now for measurement. | ||
308 | element.setStyle( 'left', left + 'px' ); | ||
309 | |||
310 | /* panel layout smartly fit the viewport size. */ | ||
311 | var panelElement = panel.element, | ||
312 | panelWindow = panelElement.getWindow(), | ||
313 | rect = element.$.getBoundingClientRect(), | ||
314 | viewportSize = panelWindow.getViewPaneSize(); | ||
315 | |||
316 | // Compensation for browsers that dont support "width" and "height". | ||
317 | var rectWidth = rect.width || rect.right - rect.left, | ||
318 | rectHeight = rect.height || rect.bottom - rect.top; | ||
319 | |||
320 | // Check if default horizontal layout is impossible. | ||
321 | var spaceAfter = rtl ? rect.right : viewportSize.width - rect.left, | ||
322 | spaceBefore = rtl ? viewportSize.width - rect.right : rect.left; | ||
323 | |||
324 | if ( rtl ) { | ||
325 | if ( spaceAfter < rectWidth ) { | ||
326 | // Flip to show on right. | ||
327 | if ( spaceBefore > rectWidth ) | ||
328 | left += rectWidth; | ||
329 | // Align to window left. | ||
330 | else if ( viewportSize.width > rectWidth ) | ||
331 | left = left - rect.left; | ||
332 | // Align to window right, never cutting the panel at right. | ||
333 | else | ||
334 | left = left - rect.right + viewportSize.width; | ||
335 | } | ||
336 | } else if ( spaceAfter < rectWidth ) { | ||
337 | // Flip to show on left. | ||
338 | if ( spaceBefore > rectWidth ) | ||
339 | left -= rectWidth; | ||
340 | // Align to window right. | ||
341 | else if ( viewportSize.width > rectWidth ) | ||
342 | left = left - rect.right + viewportSize.width; | ||
343 | // Align to window left, never cutting the panel at left. | ||
344 | else | ||
345 | left = left - rect.left; | ||
346 | } | ||
347 | |||
348 | |||
349 | // Check if the default vertical layout is possible. | ||
350 | var spaceBelow = viewportSize.height - rect.top, | ||
351 | spaceAbove = rect.top; | ||
352 | |||
353 | if ( spaceBelow < rectHeight ) { | ||
354 | // Flip to show above. | ||
355 | if ( spaceAbove > rectHeight ) | ||
356 | top -= rectHeight; | ||
357 | // Align to window bottom. | ||
358 | else if ( viewportSize.height > rectHeight ) | ||
359 | top = top - rect.bottom + viewportSize.height; | ||
360 | // Align to top, never cutting the panel at top. | ||
361 | else | ||
362 | top = top - rect.top; | ||
363 | } | ||
364 | |||
365 | // If IE is in RTL, we have troubles with absolute | ||
366 | // position and horizontal scrolls. Here we have a | ||
367 | // series of hacks to workaround it. (#6146) | ||
368 | if ( CKEDITOR.env.ie ) { | ||
369 | var offsetParent = new CKEDITOR.dom.element( element.$.offsetParent ), | ||
370 | scrollParent = offsetParent; | ||
371 | |||
372 | // Quirks returns <body>, but standards returns <html>. | ||
373 | if ( scrollParent.getName() == 'html' ) | ||
374 | scrollParent = scrollParent.getDocument().getBody(); | ||
375 | |||
376 | if ( scrollParent.getComputedStyle( 'direction' ) == 'rtl' ) { | ||
377 | // For IE8, there is not much logic on this, but it works. | ||
378 | if ( CKEDITOR.env.ie8Compat ) | ||
379 | left -= element.getDocument().getDocumentElement().$.scrollLeft * 2; | ||
380 | else | ||
381 | left -= ( offsetParent.$.scrollWidth - offsetParent.$.clientWidth ); | ||
382 | } | ||
383 | } | ||
384 | |||
385 | // Trigger the onHide event of the previously active panel to prevent | ||
386 | // incorrect styles from being applied (#6170) | ||
387 | var innerElement = element.getFirst(), | ||
388 | activePanel; | ||
389 | if ( ( activePanel = innerElement.getCustomData( 'activePanel' ) ) ) | ||
390 | activePanel.onHide && activePanel.onHide.call( this, 1 ); | ||
391 | innerElement.setCustomData( 'activePanel', this ); | ||
392 | |||
393 | element.setStyles( { | ||
394 | top: top + 'px', | ||
395 | left: left + 'px' | ||
396 | } ); | ||
397 | element.setOpacity( 1 ); | ||
398 | |||
399 | callback && callback(); | ||
400 | }, this ); | ||
401 | |||
402 | panel.isLoaded ? panelLoad() : panel.onLoad = panelLoad; | ||
403 | |||
404 | CKEDITOR.tools.setTimeout( function() { | ||
405 | var scrollTop = CKEDITOR.env.webkit && CKEDITOR.document.getWindow().getScrollPosition().y; | ||
406 | |||
407 | // Focus the panel frame first, so blur gets fired. | ||
408 | this.focus(); | ||
409 | |||
410 | // Focus the block now. | ||
411 | block.element.focus(); | ||
412 | |||
413 | // #10623, #10951 - restore the viewport's scroll position after focusing list element. | ||
414 | if ( CKEDITOR.env.webkit ) | ||
415 | CKEDITOR.document.getBody().$.scrollTop = scrollTop; | ||
416 | |||
417 | // We need this get fired manually because of unfired focus() function. | ||
418 | this.allowBlur( true ); | ||
419 | this._.editor.fire( 'panelShow', this ); | ||
420 | }, 0, this ); | ||
421 | }, CKEDITOR.env.air ? 200 : 0, this ); | ||
422 | this.visible = 1; | ||
423 | |||
424 | if ( this.onShow ) | ||
425 | this.onShow.call( this ); | ||
426 | }, | ||
427 | |||
428 | /** | ||
429 | * Repositions the panel with the same parameters that were used in the last {@link #showBlock} call. | ||
430 | * | ||
431 | * @since 4.5.4 | ||
432 | */ | ||
433 | reposition: function() { | ||
434 | var blockParams = this._.showBlockParams; | ||
435 | |||
436 | if ( this.visible && this._.showBlockParams ) { | ||
437 | this.hide(); | ||
438 | this.showBlock.apply( this, blockParams ); | ||
439 | } | ||
440 | }, | ||
441 | |||
442 | /** | ||
443 | * Restores the last focused element or simply focuses the panel window. | ||
444 | */ | ||
445 | focus: function() { | ||
446 | // Webkit requires to blur any previous focused page element, in | ||
447 | // order to properly fire the "focus" event. | ||
448 | if ( CKEDITOR.env.webkit ) { | ||
449 | var active = CKEDITOR.document.getActive(); | ||
450 | active && !active.equals( this._.iframe ) && active.$.blur(); | ||
451 | } | ||
452 | |||
453 | // Restore last focused element or simply focus panel window. | ||
454 | var focus = this._.lastFocused || this._.iframe.getFrameDocument().getWindow(); | ||
455 | focus.focus(); | ||
456 | }, | ||
457 | |||
458 | /** | ||
459 | * @todo | ||
460 | */ | ||
461 | blur: function() { | ||
462 | var doc = this._.iframe.getFrameDocument(), | ||
463 | active = doc.getActive(); | ||
464 | |||
465 | active && active.is( 'a' ) && ( this._.lastFocused = active ); | ||
466 | }, | ||
467 | |||
468 | /** | ||
469 | * Hides the panel. | ||
470 | * | ||
471 | * @todo | ||
472 | */ | ||
473 | hide: function( returnFocus ) { | ||
474 | if ( this.visible && ( !this.onHide || this.onHide.call( this ) !== true ) ) { | ||
475 | this.hideChild(); | ||
476 | // Blur previously focused element. (#6671) | ||
477 | CKEDITOR.env.gecko && this._.iframe.getFrameDocument().$.activeElement.blur(); | ||
478 | this.element.setStyle( 'display', 'none' ); | ||
479 | this.visible = 0; | ||
480 | this.element.getFirst().removeCustomData( 'activePanel' ); | ||
481 | |||
482 | // Return focus properly. (#6247) | ||
483 | var focusReturn = returnFocus && this._.returnFocus; | ||
484 | if ( focusReturn ) { | ||
485 | // Webkit requires focus moved out panel iframe first. | ||
486 | if ( CKEDITOR.env.webkit && focusReturn.type ) | ||
487 | focusReturn.getWindow().$.focus(); | ||
488 | |||
489 | focusReturn.focus(); | ||
490 | } | ||
491 | |||
492 | delete this._.lastFocused; | ||
493 | this._.showBlockParams = null; | ||
494 | |||
495 | this._.editor.fire( 'panelHide', this ); | ||
496 | } | ||
497 | }, | ||
498 | |||
499 | /** | ||
500 | * @todo | ||
501 | */ | ||
502 | allowBlur: function( allow ) { | ||
503 | // Prevent editor from hiding the panel. (#3222) | ||
504 | var panel = this._.panel; | ||
505 | if ( allow !== undefined ) | ||
506 | panel.allowBlur = allow; | ||
507 | |||
508 | return panel.allowBlur; | ||
509 | }, | ||
510 | |||
511 | /** | ||
512 | * Shows the specified panel as a child of one block of this one. | ||
513 | * | ||
514 | * @param {CKEDITOR.ui.floatPanel} panel | ||
515 | * @param {String} blockName | ||
516 | * @param {CKEDITOR.dom.element} offsetParent Positioned parent. | ||
517 | * @param {Number} corner | ||
518 | * | ||
519 | * * For LTR (left to right) oriented editor: | ||
520 | * * `1` = top-left | ||
521 | * * `2` = top-right | ||
522 | * * `3` = bottom-right | ||
523 | * * `4` = bottom-left | ||
524 | * * For RTL (right to left): | ||
525 | * * `1` = top-right | ||
526 | * * `2` = top-left | ||
527 | * * `3` = bottom-left | ||
528 | * * `4` = bottom-right | ||
529 | * | ||
530 | * @param {Number} [offsetX=0] | ||
531 | * @param {Number} [offsetY=0] | ||
532 | * @todo | ||
533 | */ | ||
534 | showAsChild: function( panel, blockName, offsetParent, corner, offsetX, offsetY ) { | ||
535 | // Skip reshowing of child which is already visible. | ||
536 | if ( this._.activeChild == panel && panel._.panel._.offsetParentId == offsetParent.getId() ) | ||
537 | return; | ||
538 | |||
539 | this.hideChild(); | ||
540 | |||
541 | panel.onHide = CKEDITOR.tools.bind( function() { | ||
542 | // Use a timeout, so we give time for this menu to get | ||
543 | // potentially focused. | ||
544 | CKEDITOR.tools.setTimeout( function() { | ||
545 | if ( !this._.focused ) | ||
546 | this.hide(); | ||
547 | }, 0, this ); | ||
548 | }, this ); | ||
549 | |||
550 | this._.activeChild = panel; | ||
551 | this._.focused = false; | ||
552 | |||
553 | panel.showBlock( blockName, offsetParent, corner, offsetX, offsetY ); | ||
554 | this.blur(); | ||
555 | |||
556 | /* #3767 IE: Second level menu may not have borders */ | ||
557 | if ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) { | ||
558 | setTimeout( function() { | ||
559 | panel.element.getChild( 0 ).$.style.cssText += ''; | ||
560 | }, 100 ); | ||
561 | } | ||
562 | }, | ||
563 | |||
564 | /** | ||
565 | * @todo | ||
566 | */ | ||
567 | hideChild: function( restoreFocus ) { | ||
568 | var activeChild = this._.activeChild; | ||
569 | |||
570 | if ( activeChild ) { | ||
571 | delete activeChild.onHide; | ||
572 | delete this._.activeChild; | ||
573 | activeChild.hide(); | ||
574 | |||
575 | // At this point focus should be moved back to parent panel. | ||
576 | restoreFocus && this.focus(); | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | } ); | ||
581 | |||
582 | CKEDITOR.on( 'instanceDestroyed', function() { | ||
583 | var isLastInstance = CKEDITOR.tools.isEmpty( CKEDITOR.instances ); | ||
584 | |||
585 | for ( var i in panels ) { | ||
586 | var panel = panels[ i ]; | ||
587 | // Safe to destroy it since there're no more instances.(#4241) | ||
588 | if ( isLastInstance ) | ||
589 | panel.destroy(); | ||
590 | // Panel might be used by other instances, just hide them.(#4552) | ||
591 | else | ||
592 | panel.element.hide(); | ||
593 | } | ||
594 | // Remove the registration. | ||
595 | isLastInstance && ( panels = {} ); | ||
596 | |||
597 | } ); | ||
598 | } )(); | ||