· 6 years ago · Oct 17, 2019, 11:00 AM
1/*
2** Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
3*/
4
5function AdfDhtmlPopupWindow()
6{
7 this.Init();
8}
9
10AdfObject.createSubclass(AdfDhtmlPopupWindow, AdfAbstractFloatingElement);
11
12// Hints that may be used before the class initialization.
13AdfDhtmlPopupWindow.HINT_ALIGN_ELEMENT = "alignElement";
14AdfDhtmlPopupWindow.HINT_MOUSEPOSITION = "mousePosition";
15AdfDhtmlPopupWindow.HINT_POSITION_CENTER = "screenCenterPosition"
16
17AdfDhtmlPopupWindow.HINT_TYPE = "type";
18AdfDhtmlPopupWindow.HINT_TYPE_MENU = "menu";
19AdfDhtmlPopupWindow.HINT_TYPE_NOTEWINDOW = "noteWindow";
20AdfDhtmlPopupWindow.HINT_TYPE_DIALOG = "dialogWindow";
21AdfDhtmlPopupWindow.HINT_TYPE_INLINESELECTOR = "inlineSelector";
22AdfDhtmlPopupWindow.HINT_TYPE_LOVCOMBOBOX = "lovCombobox";
23AdfDhtmlPopupWindow.HINT_TYPE_LAYER = "layer";
24
25/* title name for the popup that is included for screen reader mode menu type popups */
26AdfDhtmlPopupWindow.HINT_TITLE = "title";
27
28/* boolean value indicating if focus should be placed in popup */
29AdfDhtmlPopupWindow.HINT_FOCUS = "focus";
30
31AdfDhtmlPopupWindow.COMPONENT_EVENTS_ENABLED = "componentEventsEnabled";
32
33AdfDhtmlPopupWindow.HINT_AUTODISMISS_POPUP_TIMEOUT = "autodismissPopupTimeout";
34
35/* autodismissal hints */
36AdfDhtmlPopupWindow.HINT_AUTODISMISS = "autodismiss";
37// Id of the dom element to be used for autodismiss on mouseout
38AdfDhtmlPopupWindow.HINT_AUTODISMISS_NEVER = "autodismissNever";
39
40AdfDhtmlPopupWindow.HINT_AUTODISMISS_ALWAYS = "autodismissAlways";
41AdfDhtmlPopupWindow.HINT_AUTODISMISS_TIMEOUT = "autodismissTimeout";
42
43/**
44 * @deprecated private hint deprecated. Use public hint AdfRichPopup.HINT_LAUNCH_ID.
45 */
46AdfDhtmlPopupWindow.HINT_LAUNCH_SOURCE_ID = "launchId";
47
48AdfDhtmlPopupWindow.HINT_AUTODISMISS_MENU = "autodismissMenu";
49
50AdfDhtmlPopupWindow.HINT_AUTODISMISS_MOUSEOUT = "autodismissMouseOut";
51AdfDhtmlPopupWindow.HINT_AUTODISMISS_MOUSEOUT_ID = "autodismissMouseOut";
52
53AdfDhtmlPopupWindow.HINT_AUTODISMISS_INACTIVATE = "autodismissInactivate";
54
55AdfDhtmlPopupWindow.HINT_CLOSE_ON_ESCAPE = "closeOnEscape";
56AdfDhtmlPopupWindow.HINT_MAX_WIDTH = "maxWidth";
57
58AdfDhtmlPopupWindow.HINT_OPENED_HANDLER = "openedHandler";
59AdfDhtmlPopupWindow.HINT_OPENED_HANDLER_PARAM = "openedHandlerParam";
60
61AdfDhtmlPopupWindow.HINT_ALIGN = "align";
62AdfDhtmlPopupWindow.HINT_MODAL = "modal";
63AdfDhtmlPopupWindow.HINT_CONTENT = "content";
64AdfDhtmlPopupWindow.HINT_DRAG_ELEMENT = "dragElement";
65AdfDhtmlPopupWindow.HINT_LEFT_POSITION = "leftPosition";
66AdfDhtmlPopupWindow.HINT_TOP_POSITION = "topPosition";
67
68AdfDhtmlPopupWindow.HINT_CLOSE_HANDLER = "closeHandler";
69AdfDhtmlPopupWindow.HINT_CLOSE_HANDLER_PARAM = "closeHandlerParam";
70AdfDhtmlPopupWindow.HINT_DETACH_DRAG_START_HANDLER = "detachDragStartHandler";
71AdfDhtmlPopupWindow.HINT_DETACH_DRAG_END_HANDLER = "detachDragEndHandler";
72AdfDhtmlPopupWindow.HINT_COMPONENT_CLIENT_ID = "componentId";
73
74AdfDhtmlPopupWindow.HINT_ANIMATE = "animate";
75AdfDhtmlPopupWindow.HINT_RESTORE_IMMEDIATE = "restoreImmediate"
76
77// aria-label key for the element carrying role="dialog"
78AdfDhtmlPopupWindow.ARIA_LABEL= "ariaLabel" ;
79
80// hint to allow inline popup in screen reader mode
81AdfDhtmlPopupWindow.HINT_UNSCOPED = "unscoped";
82AdfDhtmlPopupWindow.HINT_UNSCOPED_ALWAYS = "always";
83
84/**
85 * Holds the name of the expando property added to the contentDom of the AdfDhtmlPopupWindow.HINT_CLOSE_HANDLER_PARAM
86 * when the floating element is dismissed by calling cancel.
87 */
88AdfDhtmlPopupWindow.__CANCELED_EXPANDO = "_isCanceled";
89AdfDhtmlPopupWindow.__REPLACEDOM_EXPANDO = "_isReplaceDom"
90AdfDhtmlPopupWindow.__POPUPID_EXPANDO = "data-afr-popupid";
91AdfDhtmlPopupWindow.__POPUP_CONTAINER_ID = "popup-container";
92AdfDhtmlPopupWindow.__POPUP_TITLE_ID = "title";
93
94AdfDhtmlPopupWindow._SLIDE_UP = "up";
95AdfDhtmlPopupWindow._SLIDE_DOWN = "down";
96AdfDhtmlPopupWindow._SLIDE_LEFT = "left";
97AdfDhtmlPopupWindow._SLIDE_RIGHT = "right";
98
99// In full screen popup mode, this attribute will be set on all ZOrderLayerContainer siblings
100// or to document body with existing display style value
101AdfDhtmlPopupWindow._FULL_SCREEN_EXPANDO = "afr-old-pop-style";
102
103// AdfDhtmlPopupWindow._POPUP_FULLSCREEN: Indicates that the popup will stretch
104// corner to corner, covering the entire screen space.
105//AdfDhtmlPopupWindow._POPUP_FULLSCREEN = "_afr_mobile_fullScreenPopup";
106
107// AdfDhtmlPopupWindow._POPUP_FULLHEIGHTPARTIALSCREEN: Indicates that the popup
108// will stretch to fill the height of the screen but may not cover the entire
109// screen width.
110//AdfDhtmlPopupWindow._POPUP_FULLHEIGHTPARTIALSCREEN = "_afr_mobile_fullHeightPartialScreenPopup";
111
112//AdfDhtmlPopupWindow._POPUP_PARTIALSCREEN: DOes not stretch
113//AdfDhtmlPopupWindow._POPUP_PARTIALSCREEN = "_afr_mobile_partialScreenPopup";
114
115// Note the current observed height of the navigator and mention that 75 is a safe
116// guesstimate to cover past and future nav bar heights.
117//AdfDhtmlPopupWindow._SCROLL_RESIZE_THRESHOLD = 75;
118AdfDhtmlPopupWindow.InitClass = function()
119{
120 // expandos - use short component id names for performance
121 this._SCROLL_POSITION = "_afrSclPtn";
122
123 // expando used to mark the temporary wrapper div created during animation
124 this._ANIMATE_WRAPPER_EXPANDO = "data-afr-taw";
125
126 this._POPUP_TAIL_TOP_LEFT_STYLECLASS = "AFPopupTailTopLeft";
127 this._POPUP_TAIL_TOP_RIGHT_STYLECLASS = "AFPopupTailTopRight";
128 this._POPUP_TAIL_TOP_CENTER_STYLECLASS = "AFPopupTailTopCenter";
129 this._POPUP_TAIL_BOTTOM_LEFT_STYLECLASS = "AFPopupTailBottomLeft";
130 this._POPUP_TAIL_BOTTOM_RIGHT_STYLECLASS = "AFPopupTailBottomRight";
131 this._POPUP_TAIL_BOTTOM_CENTER_STYLECLASS = "AFPopupTailBottomCenter";
132 this._POPUP_TAIL_MIDDLE_LEFT_STYLECLASS = "AFPopupTailMiddleLeft";
133 this._POPUP_TAIL_MIDDLE_RIGHT_STYLECLASS = "AFPopupTailMiddleRight";
134
135 this._POPUP_TAIL_STYLECLASS = "AFPopupTail";
136 this._POPUP_TAIL_SIMPLE_STYLECLASS = "AFPopupTailSimple";
137}
138
139AdfDhtmlPopupWindow.prototype.Init = function()
140{
141 // call super
142 AdfDhtmlPopupWindow.superclass.Init.call(this, AdfDhtmlZOrderManager.FLOATINGTYPE_WINDOW);
143
144 var rootElement = this.CreateDomElement();
145 // use setElement method to make sure element gets added to the correct layer
146 this.setElement(rootElement);
147 rootElement.style.display = "none";
148
149 // this._componentId;
150 // this._sizeTimeout;
151
152 // this._openedHandler;
153 // this._openedHandlerParam;
154
155 // this._positionManagerIndex = undefined;
156 // this._restoreFocusId = null;
157 // this._maxWidth = undefined;
158
159 // The duration of the animation
160 // this._animationDuration = undefined;
161
162 // this._animating = undefined;
163}
164
165/**
166 * Create and initialize the html. Subclasses must override this method
167 * @return {HTMLElement} the root dom element of this popup.
168 */
169AdfDhtmlPopupWindow.prototype.CreateDomElement = function()
170{
171 AdfAssert.failedInAbstractFunction();
172}
173
174/**
175 * Resultant indicates if popup window should hide on clip. This behavior is by default true
176 * for non-touch platforms but is inactivated for touch devices.
177 *
178 * @return {Boolean} if popup window should hide on clip
179 */
180AdfDhtmlPopupWindow.prototype.ShouldHideOnClip= function()
181{
182 return !AdfAgent.AGENT.isTouchFirstDevice();
183}
184
185AdfDhtmlPopupWindow.prototype.getInitialPopupTailPosition = function(alignHint)
186{
187 if (!alignHint)
188 {
189 return;
190 }
191
192 var popupTailPosition;
193
194 switch (alignHint)
195 {
196 case AdfRichPopup.ALIGN_AFTER_START:
197 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_TOP_LEFT_STYLECLASS;
198 break;
199 case AdfRichPopup.ALIGN_AFTER_END:
200 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_TOP_RIGHT_STYLECLASS;
201 break;
202 case AdfRichPopup.ALIGN_AFTER_CENTER:
203 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_TOP_CENTER_STYLECLASS;
204 break;
205 case AdfRichPopup.ALIGN_BEFORE_START:
206 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_BOTTOM_LEFT_STYLECLASS;
207 break;
208 case AdfRichPopup.ALIGN_BEFORE_END:
209 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_BOTTOM_RIGHT_STYLECLASS;
210 break;
211 case AdfRichPopup.ALIGN_BEFORE_CENTER:
212 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_BOTTOM_CENTER_STYLECLASS;
213 break;
214 case AdfRichPopup.ALIGN_END_AFTER:
215 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_BOTTOM_LEFT_STYLECLASS;
216 break;
217 case AdfRichPopup.ALIGN_END_BEFORE:
218 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_TOP_LEFT_STYLECLASS;
219 break;
220 case AdfRichPopup.ALIGN_END_CENTER:
221 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_MIDDLE_LEFT_STYLECLASS;
222 break;
223 case AdfRichPopup.ALIGN_START_AFTER:
224 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_BOTTOM_RIGHT_STYLECLASS;
225 break;
226 case AdfRichPopup.ALIGN_START_BEFORE:
227 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_TOP_RIGHT_STYLECLASS;
228 break;
229 case AdfRichPopup.ALIGN_START_CENTER:
230 popupTailPosition = AdfDhtmlPopupWindow._POPUP_TAIL_MIDDLE_RIGHT_STYLECLASS;
231 break;
232 default:
233 popupTailPosition = "";
234 }
235
236 return popupTailPosition;
237}
238
239AdfDhtmlPopupWindow.prototype._adjustPopupPosition = function(top, left, tailPosition)
240{
241
242 if (!this._tailElement)
243 {
244 return {"left": left, "top": top};
245 }
246 var tailWidth = this._tailElement.offsetWidth;
247 var tailHeight = this._tailElement.offsetHeight;
248
249 switch (tailPosition)
250 {
251 case AdfDhtmlPopupWindow._POPUP_TAIL_TOP_LEFT_STYLECLASS:
252 case AdfDhtmlPopupWindow._POPUP_TAIL_BOTTOM_LEFT_STYLECLASS:
253 left += tailWidth;
254 break;
255 case AdfDhtmlPopupWindow._POPUP_TAIL_MIDDLE_LEFT_STYLECLASS:
256 left +=tailWidth;
257 var rootHeight = this.getElement().offsetHeight;
258 var topPercent = Math.round((((rootHeight / 2) - (tailHeight / 2)) / rootHeight) * 100);
259 this._tailElement.style.top = topPercent + '%';
260 break;
261 case AdfDhtmlPopupWindow._POPUP_TAIL_TOP_RIGHT_STYLECLASS:
262 case AdfDhtmlPopupWindow._POPUP_TAIL_BOTTOM_RIGHT_STYLECLASS:
263 left -= tailWidth;
264 break;
265 case AdfDhtmlPopupWindow._POPUP_TAIL_MIDDLE_RIGHT_STYLECLASS:
266 left -=tailWidth;
267 var rootHeight = this.getElement().offsetHeight;
268 var topPercent = Math.round((((rootHeight / 2) - (tailHeight / 2)) / rootHeight) * 100);
269 this._tailElement.style.top = topPercent + '%';
270 break;
271 case AdfDhtmlPopupWindow._POPUP_TAIL_TOP_CENTER_STYLECLASS:
272 top +=tailHeight;
273 var rootWidth = this.getElement().offsetWidth;
274 var leftPercent = Math.round((((rootWidth / 2) - (tailWidth / 2)) / rootWidth) * 100);
275 this._tailElement.style.left = leftPercent + '%';
276 break;
277 case AdfDhtmlPopupWindow._POPUP_TAIL_BOTTOM_CENTER_STYLECLASS:
278 top -=tailHeight;
279 var rootWidth = this.getElement().offsetWidth;
280 var leftPercent = Math.round((((rootWidth / 2) - (tailWidth / 2)) / rootWidth) * 100);
281 this._tailElement.style.left = leftPercent + '%';
282 break;
283 default:
284 top = top;
285 left = left;
286 }
287
288 return {"left": left, "top": top};
289}
290
291AdfDhtmlPopupWindow.prototype.setPosition = function(top, left)
292{
293
294 var positionManagerIndex = this.GetPositionManagerIndex();
295 if(positionManagerIndex >=0 && this._tailElement)
296 {
297 var behavior = AdfPage.PAGE.getPositionManager().getComputedBehavior(positionManagerIndex);
298
299 if(behavior)
300 {
301 var verticalBehavior = behavior.verticalBehavior;
302 var horizontalBehavior = behavior.horizontalBehavior;
303 var styleClass = "AFPopupTail";
304
305 switch(verticalBehavior.floatingElementAnchor)
306 {
307 case AdfDhtmlPositionManager.TOP:
308 styleClass += "Top";
309 break;
310 case AdfDhtmlPositionManager.BOTTOM:
311 styleClass += "Bottom";
312 break;
313 case AdfDhtmlPositionManager.MIDDLE:
314 styleClass += "Middle";
315 break;
316 default:
317 AdfAssert.assert(false, "Invalid floatingElementAnchor for verticalBehavior provided.");
318 AdfLogger.LOGGER.warning("Invalid floatingElementAnchor for verticalBehavior provided.");
319 break;
320 }
321
322 switch(horizontalBehavior.floatingElementAnchor)
323 {
324 case AdfDhtmlPositionManager.LEFT:
325 styleClass += "Left";
326 break;
327 case AdfDhtmlPositionManager.RIGHT:
328 styleClass += "Right";
329 break;
330 case AdfDhtmlPositionManager.CENTER:
331 styleClass += "Center";
332 break;
333 default:
334 AdfAssert.assert(false, "Invalid floatingElementAnchor for horizontalBehavior provided.");
335 AdfLogger.LOGGER.warning("Invalid floatingElementAnchor for horizontalBehavior provided.");
336 break;
337 }
338
339 AdfDomUtils.removeCSSClassName(this._tailElement,this._tailPosition);
340 this._tailPosition = styleClass;
341 AdfDomUtils.addCSSClassName(this._tailElement, styleClass);
342 var newPosition = this._adjustPopupPosition(top, left, styleClass);
343 top = newPosition["top"];
344 left = newPosition["left"];
345 }
346 }
347
348 AdfDhtmlPopupWindow.superclass.setPosition.call(this, top, left);
349}
350
351AdfDhtmlPopupWindow.prototype.getTailElement = function()
352{
353 return this._tailElement;
354}
355
356/**
357 * Determines if the popup has a different rendering in screen reader mode as compared to
358 * the normal mode.
359 */
360AdfDhtmlPopupWindow.prototype.hasSpecialRenderingForScreenReader = function()
361{
362 return !!AdfPopupScopingUtils.isScopingContainer(this.getElement());
363}
364
365/**
366 * Returns true if screen reader mode is on and the popup has a 'regular' screen reader mode popup.
367 * @return true if screen reader mode is on and the popup has a 'regular' screen reader mode popup.
368 */
369 AdfDhtmlPopupWindow.prototype.isScreenReaderModePopup = function()
370 {
371 return (AdfPage.PAGE.isScreenReaderMode() && this.hasSpecialRenderingForScreenReader())
372 }
373
374/**
375 * Displays a popup window on the screen.
376 *
377 * @param {Object:null} hints a set of popup hints (see {@link AdfDhtmlPopupWindow})
378 * @see #hide
379 */
380AdfDhtmlPopupWindow.prototype.show = function(hints)
381{
382 AdfAssert.assertObject(hints, "Cannot show a popup element without hints");
383
384 // Start with timing
385
386 var componentId = hints[AdfDhtmlPopupWindow.HINT_COMPONENT_CLIENT_ID];
387 AdfPage.PAGE.__perfTimings(false, false, true, "popup show called: type=" + hints[AdfDhtmlPopupWindow.HINT_TYPE] + ", id=" + componentId); //changed
388
389 // save the component id of the popup
390 this._componentId = componentId;
391
392 var alignElement = hints[AdfDhtmlPopupWindow.HINT_ALIGN_ELEMENT];
393 this.setAlignElement(alignElement);
394
395 var align = hints[AdfRichPopup.HINT_ALIGN];
396 var restoreImmediate = hints[AdfDhtmlPopupWindow.HINT_RESTORE_IMMEDIATE];
397
398 this._closingAnimationHints = new Object;
399 this._closingAnimationHints[AdfDhtmlPopupHints.CLOSE_TRANSITION] = hints[AdfDhtmlPopupHints.CLOSE_TRANSITION];
400
401 // flag indicates the opening hander has not been called yet. This should only happen once.
402 this._isOpening = true;
403
404 // Popup opened event handler. The callback will be fired after the
405 // popup becomes visible to allow overriding focus.
406 this._openedHandler = hints[AdfDhtmlPopupWindow.HINT_OPENED_HANDLER];
407 this._openedHandlerParam = hints[AdfDhtmlPopupWindow.HINT_OPENED_HANDLER_PARAM];
408
409 var mousePosition = hints[AdfDhtmlPopupWindow.HINT_MOUSEPOSITION];
410 var autoDismiss = hints[AdfDhtmlPopupWindow.HINT_AUTODISMISS];
411
412 var screenCenterPosition = hints[AdfDhtmlPopupWindow.HINT_POSITION_CENTER];
413
414 // popup hint redirection for backwards compatibility
415 if (autoDismiss === true)
416 hints[AdfDhtmlPopupWindow.HINT_AUTODISMISS] = AdfDhtmlPopupWindow.HINT_AUTODISMISS_ALWAYS;
417
418 //AdfDhtmlPopupMenu subclass handles its own escape logic when not in screen reader mode
419 var closeOnEscape = hints[AdfDhtmlPopupWindow.HINT_CLOSE_ON_ESCAPE];
420 if (closeOnEscape == null)
421 {
422 // default is true
423 closeOnEscape = true;
424 }
425 this._closeOnEscape = closeOnEscape;
426
427 // client id of the launching source. if provided, included in escape handling
428 // also used by the AdfAutoDismissalManager for inline with HINT_AUTODISMISS_ALWAYS
429 this._launchSourceId = hints[AdfRichPopup.HINT_LAUNCH_ID];
430
431 // look for a max-width popup hint
432 var maxWidth = hints[AdfDhtmlPopupWindow.HINT_MAX_WIDTH];
433 if (maxWidth)
434 {
435 // if it has a value make sure it's numeric
436 AdfAssert.assertNumeric(maxWidth, "AdfDhtmlPopupWindow.HINT_MAX_WIDTH");
437 this._maxWidth = maxWidth;
438 }
439
440 var page = AdfPage.PAGE;
441 var component = page.findComponent(componentId);
442 AdfAssert.assert(component!=null, "Cannot show a popup element without a valid component");
443 this.getElement().id = AdfRichUIPeer.createSubId(componentId, AdfDhtmlPopupWindow.__POPUP_CONTAINER_ID);
444
445 // focus hint determines if by default focus should be established when the popup opens.
446 // for certain popup subclasses like the AdfDhtmNoteWindowPopupSelector, focus is turned off.
447 var focusHint = hints[AdfDhtmlPopupWindow.HINT_FOCUS];
448 if (focusHint == null)
449 focusHint = true; // default is true
450
451 // popups that are not notewindow get focus by default
452 // however, if we are in screen reader mode, we must establish focus in the popup
453 // since it will be the only thing visible
454 var hasSpecialRenderingForScreenReader = this.hasSpecialRenderingForScreenReader();
455 if (hints[AdfDhtmlPopupWindow.HINT_TYPE] != AdfDhtmlPopupWindow.HINT_TYPE_DIALOG)
456 focusHint = focusHint || hasSpecialRenderingForScreenReader;
457
458 // if restore immediate, the focus path before PPR is restored. This means that
459 // restoreImmediate only applies to a PPR.
460 if (restoreImmediate)
461 focusHint = false;
462
463 if(focusHint)
464 {
465 // If we are going to move the focus to the popup, first stash away
466 // the currently focused element's id so that we can restore the focus when
467 // we hide the popup.
468 var activeDomElement = page.getActiveDomElement();
469 if(activeDomElement)
470 {
471 var restoreId = activeDomElement.id;
472
473 // If the activeDomElement doesn't have an id, use the component id instead.
474 if(!restoreId)
475 {
476 restoreId = page.getActiveComponentId();
477
478 // If there's also no active component id, assign a unique id to the element.
479 // If this element gets PPRed, then we will not be able to restore focus to this element.
480 if (!restoreId)
481 {
482 restoreId = activeDomElement.id = (new Date()).getTime();
483 }
484 }
485
486 this._restoreFocusId = restoreId;
487 AdfLogger.LOGGER.fine("In AdfDhtmlPopupWindow#show(), _restoreFocusId set to " + restoreId);
488 }
489 }
490
491 // hang on to the focus hint for use by the FocusOnFirstElement
492 this.SetFocusOnOpen(focusHint);
493
494 var content = hints[AdfDhtmlPopupWindow.HINT_CONTENT];
495 if (content)
496 {
497 // Set the maximum-width of the popup. If we do not do this, and we have wide
498 // content in our popup, it will try to be 100% of the browser window's width.
499 // We can't set the table's width, because maxWidth doesn't work correctly on
500 // tables.
501 if (this._maxWidth)
502 {
503 content.style.maxWidth = this._maxWidth +"px";
504 }
505
506 // change the content to the wrapper if in screen reader mode
507 // the "begin" and "end" tags are added to the content
508 content = hints[AdfDhtmlPopupWindow.HINT_CONTENT] =
509 this.WrapContent(hints, content, hasSpecialRenderingForScreenReader);
510 this.setContent(content);
511 }
512
513 // Set/remove these attributes for all screen reader mode popups, regardless of
514 // hasSpecialRenderingForScreenReader being true or false
515 if (AdfPage.PAGE.isScreenReaderMode())
516 this.setAccessibleAttrs(hints);
517
518 var animateHint = hints[AdfDhtmlPopupWindow.HINT_ANIMATE];
519
520 // Initialize the duration of animation.
521 // animate = 'false' property will turn off the animation
522 if(page.isAnimationEnabled() && animateHint != AdfRichPopup.ANIMATE_FALSE)
523 {
524
525 var animProperty = this.GetAnimationDurationSkinProperty(hints);
526 if (animProperty)
527 {
528 //if animationDuration is zero, don't do animation
529 var animationDuration = parseInt(page.getLookAndFeel().getSkinProperty(animProperty));
530 if (animationDuration > 0)
531 {
532 animProperty = this.GetAnimateSkinProperty();
533 var animatePropertyValue = animProperty ? page.getLookAndFeel().getSkinProperty(animProperty) : null;
534
535 // If animate property value is set to "true", but skinning value is set to "false". We still want to animate
536 if (animatePropertyValue != AdfRichPopup.ANIMATE_FALSE || animateHint == AdfRichPopup.ANIMATE_TRUE)
537 {
538 this._animationDuration = animationDuration;
539 this._closingAnimationHints[AdfDhtmlPopupWindow.HINT_ANIMATE] = hints[AdfDhtmlPopupWindow.HINT_ANIMATE];
540 }
541 }
542 }
543 }
544
545 this.setCloseHandler(hints[AdfDhtmlPopupWindow.HINT_CLOSE_HANDLER]);
546 this.setCloseHandlerParam(hints[AdfDhtmlPopupWindow.HINT_CLOSE_HANDLER_PARAM]);
547
548 // if display on timeout returns true, the window will be shown after a
549 // timer thread has expired.
550 // we will not actually show the content on the screen until the timeout. This is
551 // so that all positioning and sizing is fully complete.
552 this.getElement().style.visibility = "hidden";
553
554 // registers the floating element with the position manager.
555 if(mousePosition)
556 {
557 // align defaults to after-start and by align mousePosition
558 this._positionAtMousePointer(mousePosition);
559 }
560 else if (screenCenterPosition)
561 {
562 this._positionAtScreenCenter();
563 }
564 else if (align)
565 {
566 // registers with position manager by align element or align position
567 this.Position(align);
568 }
569
570 // Let ATs know that we are launching a popup
571 this._announce("af_popup.STATUS_ENTERING_POPUP");
572
573 this.DoShow(hints);
574
575 var isFullScreen = hints[AdfDhtmlPopupHints.POPUP_FULL_SCREEN] ;
576 var isFullHeightPartialScreen = hints[AdfDhtmlPopupHints.POPUP_FULL_HEIGHT_PARTIAL_SCREEN];
577 var isPartialScreen = hints[AdfDhtmlPopupHints.POPUP_PARTIAL_SCREEN];
578 if(isPartialScreen || isFullHeightPartialScreen)
579 this._fixBodyPosition(hints);
580
581 if( isFullScreen || isFullHeightPartialScreen)
582 {
583 var panelWindow = this._getFirstPanelWindow(component,hints);
584 if(panelWindow != null)
585 if(isFullHeightPartialScreen)
586 //setTimeout( function(){ panelWindow.setContentHeight(AdfPage.PAGE.getDomWindow().innerHeight);},150);
587 AdfPage.PAGE.scheduleTimer(this, AdfDhtmlPopupWindow._setContentHeight,{'panelWindow': panelWindow}, 150, {'isSynchronized' : true});
588 if(isFullScreen)
589 //panelWindow.setContentHeight(AdfPage.PAGE.getDomWindow().innerHeight);
590 AdfDhtmlPopupWindow._setContentHeight({'panelWindow': panelWindow});
591 }
592
593 // register with the dismissal manager
594 page.getAutoDismissalManager().addBehavior(component, hints);
595
596 var domWindow = page.getDomWindow();
597
598 // key used to capture the last active dom element as a page property
599 // @see #cancel
600 var activeDomElementIdKey = AdfDhtmlPopupWindow._createFocusPagePropertyKey(componentId);
601
602 // if we are restoring the popup immediate, we have to display the popup before we restore
603 // the focus path. So, this only applies to PPR restoration.
604 if (!restoreImmediate)
605 {
606 // invokes showing the popup in a seperate thread
607 this._sizeTimeout = page.scheduleTimer(this, this.createCallback(this._size), hints, 1, {'isSynchronized' : true});
608 }
609 else
610 {
611 // Shows the popup immediately. set the timeout to a non-null. This is used to
612 // identify hide has been called before the normal window time out of 50 ms.
613 this._sizeTimeout = 0;
614 this._size(hints);
615
616 // the focus path logic in a PPR (AdfDhtmlPage#_getFocusPath) is based on the
617 // dom hierarchy versus the component hiearchy. If we have been canceled due
618 // to a dom replacement, we need to handle restoring the focus path.
619 // We capture the last active dom element id as a page property when the popup
620 // is dismissed due to a dom replacement. Note that this only applies to a PPR
621 // that knocks down the popup. If there is a last active component id and it is
622 // located under the popup and is focusable, restore focus within the popup.
623 // see #cancel & #hide
624
625 var activeDomElementId = page.getPageProperty(activeDomElementIdKey);
626 if (activeDomElementId)
627 {
628 var restoreFocusElement = AdfAgent.AGENT.getElementById(activeDomElementId);
629 if (restoreFocusElement &&
630 AdfDomUtils.isAncestor(content, restoreFocusElement) &&
631 AdfFocusUtils.isFocusable(restoreFocusElement))
632 AdfFocusUtils.focusElement(restoreFocusElement);
633 }
634 else if (AdfDhtmlDialogManager.getInstance().getActiveDialog() == this)
635 {
636 this.FocusOnFirstElement(true);
637 }
638 }
639
640 // null out the key that holds the last active dom element
641 // @see #cancel
642 page.setPageProperty(activeDomElementIdKey, null);
643 var rootElement = this.getElement();
644 rootElement.setAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO, this._getPopupExpandoId(hints));
645}
646
647AdfDhtmlPopupWindow._setContentHeight = function(state)
648{
649 state['panelWindow'].setContentHeight(AdfPage.PAGE.getDomWindow().innerHeight);
650}
651
652/**
653 * This getter exposes a popup hint that captures the popups's clientId.
654 * It is a quick way to find the owning popup component.
655 *
656 * @return {String} the clientId of the outer popup component
657 */
658AdfDhtmlPopupWindow.prototype.getPopupClientId = function()
659{
660 return this._componentId;
661}
662
663/*
664 * Invokes the opened handler callback. The callback and parameter list is passed
665 * by the invoking peer using the "HINT_CLOSE_HANDLER" and "HINT_CLOSE_HANDLER_PARAM"
666 * hint parameters.
667 *
668 * @return {void}
669 */
670AdfDhtmlPopupWindow.prototype.OpenedPopup = function(hints)
671{
672 // only run this once
673 if (!this._isOpening)
674 return;
675 delete this._isOpening;
676
677 // Queue open popup announcements after the popup is opened. Before these were getting lost on
678 // firefox when announced earlier, even when set to role alert and assertive.
679 this.announceOpeningViaLiveRegion(hints);
680
681 // register a listeners on the document
682 this._registerEventHandlers(hints);
683
684 // if the callback function doesn't exist exit
685 if(!(this._openedHandler))
686 {
687
688 // bug 16621214 - menus don't use open handlers
689 this.FocusOnFirstElement();
690
691
692 // Since we are bailing out, note perf timings.
693 // If we did not bail out, second call to perfTimings would include
694 // the handler call expense as well
695 AdfPage.PAGE.__perfTimings(false, false, true, "popup opened no handler present: id=" + this._componentId); // changed
696 return;
697 }
698
699 var domElement = this.getContent();
700 this.RestoreScrollValues(domElement);
701
702 // set defaut focus to the first tabable element
703 this.FocusOnFirstElement();
704
705 // invoke the callback passing the parameters
706 this._openedHandler(this._openedHandlerParam);
707
708 // remove references to the opended callback since this should only
709 // be invoke once
710 delete this._openedHandler;
711 delete this._openedHandlerParam;
712
713 AdfPage.PAGE.__perfTimings(false, false, true, "popup opened handler present: id=" + this._componentId) // changed
714}
715
716/**
717 * Wraps the content of the popup window.
718 * @return the wrapped content
719 */
720AdfDhtmlPopupWindow.prototype.WrapContent = function(hints, content, hasSpecialRenderingForScreenReader)
721{
722 var page = AdfPage.PAGE;
723 // Wrap the popup's content in a table because IE7 can't render popups that are position:relative
724 // when the renderingDirection=rtl. By using a table we can work around this.
725 var doc = page.getDomDocument();
726 var table = doc.createElement("table");
727
728 // generate a unique id for the dynamic nodes that will hold the popup's content when shown
729 // the id is used to register a resizeListener @See #_registerEventHandlers
730 this._resizeAnchorId = table.id = AdfRichUIPeer.CreateSubId(this._componentId, "" + (new Date()).getTime());
731 AdfAgent.AGENT.elementsAdded(table);
732
733 table.cellPadding = table.cellSpacing = 0;
734 table.insertRow(0).insertCell(0).appendChild(content);
735 table.style.position = "relative";
736 table.role = "presentation";
737
738 if (hasSpecialRenderingForScreenReader)
739 {
740 var laf = page.getLookAndFeel();
741 var agent = AdfAgent.AGENT;
742 var wrapper = doc.createElement("div");
743 var closeOnEscape = this._closeOnEscape;
744
745 // Create the start boundary marker that we use to wrap the popup content in screen reader mode.
746 // Having the contents identified by a header makes the popup easily identifiable and allows a
747 // JAWS user to easily jump to the start of the popup using the header quick key. Note that this
748 // can also come in handy considering that JAWS is inconsistent about following the focus to the
749 // popup when we launch.
750 //
751 // In theory the use of h1 for the start boundary means that all nested headers inside of the
752 // popup content should be demoted by one level. However, the gains that we get by using headers
753 // here far outweight these concerns, so we're gonna to roll with this for now.
754 var startElement = doc.createElement("h1");
755 startElement.id = AdfRichUIPeer.createSubId(this._componentId, AdfDhtmlPopupWindow.__POPUP_TITLE_ID);
756
757 // Create the end text that describes how to exit the popup, like "Press escape to exit popup."
758 // Note that base on feedback from Don Mauck, our accessibility evangelist, we have updated this
759 // from an H1 element to a DIV element, as he found it odd to have a header at the end with no
760 // content. Also, he specified the new descriptive text about pressing escape.
761 var endElement = doc.createElement("div");
762
763 // Provide some basic formatting so sighted users don't freak out, like a smaller font size for
764 // the h1 tag and a little margin before the closing text.
765 startElement.style.cssText = "font-size:small";
766 endElement.style.cssText = "margin-top: 6px";
767
768 var startTitle;
769 var isMenu = hints[AdfDhtmlPopupWindow.HINT_TYPE] == AdfDhtmlPopupWindow.HINT_TYPE_MENU;
770 var isPanelDrawer = hints[AdfDhtmlPopupWindow.HINT_TYPE] == AdfDhtmlPopupWindow.HINT_TYPE_LAYER;
771 if (isMenu || isPanelDrawer)
772 {
773 // Custom top text like "File Menu"
774 var hintTitle = hints[AdfDhtmlPopupWindow.HINT_TITLE];
775 var popupTitle = (hintTitle == null) ? "" : hintTitle;
776 var keyName = isMenu ? "af_popup.TIP_START_OF_MENU" :
777 "af_popup.TIP_START_OF_TITLED_POPUP";
778 startTitle = laf.getTranslatedString(keyName, popupTitle);
779 }
780 else
781 {
782 // Generic top text of "Popup"
783 startTitle = laf.getTranslatedString("af_popup.TIP_START_OF_POPUP");
784 }
785
786 var endTitle;
787 if (isMenu)
788 {
789 // Bottom text like "Press escape to exit the menu."
790 endTitle = (closeOnEscape ? laf.getTranslatedString("af_popup.TIP_END_OF_MENU") :
791 laf.getTranslatedString("af_popup.TIP_END_OF_MENU_DISABLE_CLOSE_ON_ESCAPE"));
792 }
793 else
794 {
795 // Bottom text like "Press escape to exit the popup."
796 endTitle = (closeOnEscape ? laf.getTranslatedString("af_popup.TIP_END_OF_POPUP") :
797 laf.getTranslatedString("af_popup.TIP_END_OF_POPUP_DISABLE_CLOSE_ON_ESCAPE"));
798 }
799
800 agent.setTextContent(startElement, startTitle);
801 agent.setTextContent(endElement, endTitle);
802
803 wrapper.appendChild(startElement);
804 wrapper.appendChild(table);
805 wrapper.appendChild(endElement);
806 return wrapper;
807 }
808 else
809 {
810 return table;
811 }
812}
813
814/**
815 * Registers listeners with the document.
816 */
817AdfDhtmlPopupWindow.prototype._registerEventHandlers = function(hints)
818{
819 var page = AdfPage.PAGE;
820 var agent = AdfAgent.AGENT;
821 var doc = page.getDomDocument();
822 var popupContainer = this.getElement();
823
824 if (!hints || !hints[AdfDhtmlPopupWindow.COMPONENT_EVENTS_ENABLED])
825 {
826 // listen for key up that bubbles up to the document
827 var keyUpCallback = this._keyUpCallback = this.createCallback(this._handleKeyUp);
828 agent.addBubbleEventListener(doc, "keyup", keyUpCallback);
829
830 // listen for key down events that bubble up to the popup-container
831 var keyDownCallback = this._keyDownCallback = this.createCallback(this._handleKeyDown);
832 agent.addBubbleEventListener(popupContainer, "keydown", keyDownCallback);
833 }
834
835 // insist the element has an id. This id is used to register resize notification listeners
836 // that will autosize the popup when the dom has changed.
837 var element = this.getElement().firstChild;
838
839 var resizeCallback = this._resizeCallback = this.createCallback(this._handleResize);
840 agent.addResizeListener(this._resizeAnchorId, resizeCallback);
841 if (hints[AdfDhtmlPopupHints.POPUP_FULL_SCREEN] || hints[AdfDhtmlPopupHints.POPUP_FULL_HEIGHT_PARTIAL_SCREEN])
842 {
843 this._reCalcHeightCallback = this.createCallback(this._reCalculateHeight);
844 AdfPage.PAGE.getDomDocument().addEventListener('scroll', this._reCalcHeightCallback);
845
846 this._orientationChangeCallback = this.createCallback(this._reCalculateHeightOnOrientationChange);
847 window.addEventListener("orientationchange", this._orientationChangeCallback);
848 }
849}
850/**
851 * If popup is set to be displayed in full screen mode or full height partial screen mode,
852 * this method will readjust height of popup on scroll event triggered on document.
853 * This is required on touch devices that show/hide the nav bar dynamically in
854 * response to the scroll. This handler will ensure that the popup adjusts to
855 * accommodate for the presence or absence of the nav bar during the scroll.
856 */
857AdfDhtmlPopupWindow.prototype._reCalculateHeight = function()
858{
859 var element = this.getElement();
860 var newHeight = AdfPage.PAGE.getDomWindow().innerHeight;
861 element.style.maxHeight = newHeight +"px";
862 var content = this.getContent();
863 this.DoResizeNotifyDom(content);
864
865}
866
867/**
868 * If popup is set to be displayed in full screen mode or full height partial screen mode,
869 * this method will readjust height of popup on orientation change event triggered on window.
870 * This is required on touch devices, when user moves from portrait to landscape mode or viceversa,
871 * this handler will ensure that the popup adjusts height to fit the available height on screen
872 * for the presence or absence of the nav bar during the orientation.
873 */
874AdfDhtmlPopupWindow.prototype._reCalculateHeightOnOrientationChange = function()
875{
876 var element = this.getElement();
877 setTimeout( function(){ element.style.maxHeight = AdfPage.PAGE.getDomWindow().innerHeight + "px"; },150);
878 //AdfPage.PAGE.scheduleTimer(this, AdfDhtmlPopupWindow._setContentHeight,{'panelWindow': panelWindow}, 150, {'isSynchronized' : true});
879 var content = this.getContent();
880 this.DoResizeNotifyDom(content);
881
882}
883
884/**
885 * Utility method to query popup id.
886 */
887AdfDhtmlPopupWindow.prototype._getPopupExpandoId = function(hints)
888{
889 if (hints[AdfDhtmlPopupHints.SURROGATE_CLIENT_ID])
890 {
891 // pannel draw uses a surrogate DIV to mark where the popup was defined before it is reparented to the zorder container
892 // when open versus using subids and leaving the root popup dom in place in the document.
893 return hints[AdfDhtmlPopupHints.SURROGATE_CLIENT_ID];
894 }
895 else
896 {
897 // bug 15931488
898 // assigns the popupId to the root element created on the client to hold the
899 // popups content. This is used by the auto dismissal manager to associate dom
900 // dynamically created on the client with the target popup.
901 return this._componentId;
902 }
903}
904
905/**
906 * If popup is set to be dispalyed in full screen mode by setting property
907 * AdfDhtmlPopupHints.POPUP_FULL_SCREEN, 'displaye:none' will be added on all sibling of 'ZOrderLayerContainer'
908 */
909AdfDhtmlPopupWindow.prototype._hideZOrderLayerContainerSiblings = function(hints)
910{
911 var popupRoot = document.getElementById(AdfDhtmlZOrderManager.LAYERCONTAINER);
912 var siblings = popupRoot.parentElement.childNodes;
913 var agent = AdfAgent.AGENT;
914 var popupId = this._getPopupExpandoId(hints);
915 // In case of nested popups, first popup changes display values and restores it back on closure.
916 for (var i = 0;i < siblings.length;i++)
917 {
918 if (siblings[i] != popupRoot)
919 {
920 // In case popup is opened from another popup , no changes are needed
921 if(siblings[i].hasAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO))
922 break;
923 if (siblings[i].style.display)
924 agent.setAttribute(siblings[i], AdfDhtmlPopupWindow._FULL_SCREEN_EXPANDO, siblings[i].style.display);
925 siblings[i].style.display = 'none';
926 agent.setAttribute(siblings[i],AdfDhtmlPopupWindow.__POPUPID_EXPANDO, popupId);
927 }
928 }
929}
930/**
931 * Restores display value of all sibling of 'ZOrderLayerContainer'.
932 */
933AdfDhtmlPopupWindow.prototype._restoreZOrderLayerContainerSiblings = function()
934{
935 var popupRoot = document.getElementById(AdfDhtmlZOrderManager.LAYERCONTAINER);
936 var siblings = popupRoot.parentElement.childNodes;
937 var agent = AdfAgent.AGENT;
938 var popupId = this.getElement().getAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO)
939 for (var i = 0;i < siblings.length;i++)
940 {
941 if (siblings[i] != popupRoot)
942 {
943 // In case, popup opened by another popup closes, ignore resetting values.
944 if(siblings[i].getAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO) != popupId)
945 {
946 break;
947 }
948 var restoredValue = agent.getAttribute(siblings[i], AdfDhtmlPopupWindow._FULL_SCREEN_EXPANDO);
949 if (restoredValue)
950 siblings[i].style.display = restoredValue;
951 else
952 siblings[i].style.display = '';
953 siblings[i].removeAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO);
954 }
955 }
956}
957
958/**
959 * If popup is set to be dispalyed in partial screen mode by setting property
960 * AdfDhtmlPopupHints.POPUP_PARTIAL_SCREEN, 'position:fixed' will be added on body
961 */
962AdfDhtmlPopupWindow.prototype._fixBodyPosition = function(hints)
963{
964 var bodyElement = document.body;
965 var agent = AdfAgent.AGENT;
966
967 if (bodyElement.hasAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO))
968 return;
969
970 if (bodyElement.style.position)
971 agent.setAttribute(siblings[i], AdfDhtmlPopupWindow._FULL_SCREEN_EXPANDO, bodyElement.style.position);
972
973 var scrolledHeight = bodyElement.scrollTop;
974 agent.setAttribute(bodyElement, AdfDhtmlPopupWindow._SCROLL_POSITION, scrolledHeight);
975 bodyElement.style.position = "fixed";
976 bodyElement.style.top = scrolledHeight * -1 + "px";
977
978 agent.setAttribute(bodyElement, AdfDhtmlPopupWindow.__POPUPID_EXPANDO, this._getPopupExpandoId(hints));
979}
980
981/**
982 * Restores position value of body
983 */
984AdfDhtmlPopupWindow.prototype._undoFixBodyPosition = function()
985{
986 var bodyElement = document.body;
987 var agent = AdfAgent.AGENT;
988 var popupId = this.getElement().getAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO)
989
990 // In case, popup opened by another popup closes, ignore resetting values.
991 if(bodyElement.getAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO) != popupId)
992 return;
993
994 var restoredValue = agent.getAttribute(bodyElement, AdfDhtmlPopupWindow._FULL_SCREEN_EXPANDO);
995 if (restoredValue)
996 {
997 bodyElement.style.position = restoredValue;
998 bodyElement.removeAttribute(AdfDhtmlPopupWindow._FULL_SCREEN_EXPANDO);
999 }
1000 else
1001 bodyElement.style.position = '';
1002
1003 bodyElement.scrollTop = agent.getAttribute(bodyElement, AdfDhtmlPopupWindow._SCROLL_POSITION);
1004 bodyElement.style.top = "0px";
1005 bodyElement.removeAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO);
1006 bodyElement.removeAttribute(AdfDhtmlPopupWindow._SCROLL_POSITION);
1007}
1008
1009
1010/**
1011 * Inspects the content of the popup and returns the peer if the first child
1012 * is a AdfRichPanelWindow component. If hints are given and the HINT_TYPE_DIALOG
1013 * is not given, the content is not inspected.
1014 *
1015 * @param {AdfUIComponent} component root popup component
1016 * @param {Object:null} hints popup hints
1017 * @return {AdfDhtmlPanelWindow:null} PanelWindow if the first child is a AdfRichPanelWindow
1018 */
1019AdfDhtmlPopupWindow.prototype._getFirstPanelWindow = function(component, hints)
1020{
1021 var panelWindowPeer = null;
1022 var hintType = hints[AdfDhtmlPopupWindow.HINT_TYPE];
1023
1024 // Dig into the popup content to look for panel window peer if the type is not known or
1025 // if it is explicitly set to dialogWindow
1026 if(hintType == null || (hintType == AdfDhtmlPopupWindow.HINT_TYPE_DIALOG))
1027 {
1028 component.visitChildren(this._visitChildrenForPanelWindow, this, true);
1029 if(this._firstChildPanelWindow)
1030 {
1031 panelWindowPeer = this._firstChildPanelWindow;
1032 delete this._firstChildPanelWindow;
1033 }
1034 }
1035 return panelWindowPeer;
1036}
1037
1038/**
1039 * Callback used by _getFirstPanelWindow to visitChildren on the component.
1040 * The callback looks at the first child to see if it is a AdfRichPanelWindow.
1041 * If the first child is a PanelWindow, it is assigned to a temporary private
1042 * variable. If the child is an AdfRichRegion, the search continues
1043 *
1044 * @param {AdfUIComponent} component child component visited
1045 * @return {Number} returns a value of 2 if traversal has finished, 0 if traversal needs to continue
1046 */
1047AdfDhtmlPopupWindow.prototype._visitChildrenForPanelWindow = function(component)
1048{
1049 var domWindow = AdfPage.PAGE.getDomWindow();
1050
1051 //if the first component found is a region then we want to drill down another layer
1052 if (domWindow.AdfRichRegion && component instanceof AdfRichRegion)
1053 return 0;
1054
1055 if(domWindow.AdfRichPanelWindow && component instanceof AdfRichPanelWindow)
1056 this._firstChildPanelWindow = component;
1057
1058 return 2;
1059}
1060
1061/**
1062 * Callback invoked every time the size of the floating element changes.
1063 * @see AdfAgent#addResizeListener
1064 */
1065AdfDhtmlPopupWindow.prototype._handleResize = function()
1066{
1067 this.autoSize();
1068 var content = this.getContent();
1069 this.DoResizeNotifyDom(content);
1070 var component = page.findComponent(this._componentId);
1071 var isFullScreen = component.getProperty(AdfDhtmlPopupHints.POPUP_FULL_SCREEN);
1072 // on full screen mode reset maxHeight based on current window max height
1073 if(isFullScreen)
1074 content.style.maxHeight= AdfPage.PAGE.getDomWindow().innerHeight +"px"
1075
1076 // browser window resize event is not consistently queued for all browsers.
1077 // validate the position when detecting a content resize.
1078 if(this._positionManagerIndex != null)
1079 AdfPage.PAGE.getPositionManager().validatePosition(this._positionManagerIndex);
1080}
1081
1082/**
1083 * Unregisters listeners registered with the document.
1084 */
1085AdfDhtmlPopupWindow.prototype._unregisterEventHandlers = function()
1086{
1087
1088 var page = AdfPage.PAGE;
1089 var doc = page.getDomDocument();
1090 var agent = AdfAgent.AGENT;
1091 var popupContainer = this.getElement();
1092
1093 var keyUpCallback = this._keyUpCallback;
1094 if (keyUpCallback)
1095 {
1096 agent.removeBubbleEventListener(doc, "keyup", keyUpCallback);
1097 delete this._keyUpCallback;
1098 }
1099
1100 var keyDownCallback = this._keyDownCallback;
1101 if (keyDownCallback)
1102 {
1103 agent.removeBubbleEventListener(popupContainer, "keydown", keyDownCallback);
1104 delete this._keyDownCallback;
1105 }
1106
1107 var resizeCallback = this._resizeCallback;
1108 if (resizeCallback)
1109 {
1110 var element = this.getElement().firstChild;
1111 agent.removeResizeListener(this._resizeAnchorId, resizeCallback);
1112 delete this._resizeAnchorId;
1113 delete this._resizeCallback;
1114 }
1115 if(this._reCalcHeightCallback)
1116 {
1117 AdfPage.PAGE.getDomDocument().removeEventListener('scroll', this._reCalcHeightCallback);
1118 }
1119
1120 if(this._orientationChangeCallback)
1121 {
1122 window.removeEventListener("orientationchange", this._orientationChangeCallback);
1123 }
1124}
1125
1126/**
1127 * Hides this popup window.
1128 * @see #show
1129 */
1130AdfDhtmlPopupWindow.prototype.hide = function()
1131{
1132 // synchronize on this method using a private semaphore. If a popup is launched
1133 // using the focus trigger type, the return to focus logic will cause a race condition
1134 // unless blocked.
1135 if (this._isHiding)
1136 {
1137 return;
1138 }
1139 this._isHiding = true;
1140 AdfPage.PAGE.__perfTimings(false, false, true, "popup hide called: id=" + this._componentId);
1141
1142 // The popup is being dismissed even while the open animation is in progress.
1143 // Stop the animation and bring to opened state before proceeding further.
1144 if (this._animator && this._isOpening)
1145 {
1146 this._animator.stop();
1147 var wrapper = this.getElement().parentNode;
1148 AdfDhtmlPopupWindow.OpenAnimationComplete({wrapper:wrapper, myself:this});
1149 }
1150
1151 // If animation is enabled, then close popup with animation
1152 if (this._closingAnimationHints[AdfDhtmlPopupWindow.HINT_ANIMATE] != AdfRichPopup.ANIMATE_FALSE && this._animationDuration > 0)
1153 {
1154 this.AnimateClosing(this._closingAnimationHints);
1155 }
1156 else
1157 {
1158 // If animation is not enabled or its not of AdfRichPopup type, just hide the popup.
1159 this.ClosedPopup();
1160 }
1161
1162}
1163
1164/**
1165 * Hides this popup window from dom.
1166 * @see #show
1167 */
1168AdfDhtmlPopupWindow.prototype.ClosedPopup = function()
1169{
1170 // Let ATs know that we are leaving a popup
1171 this._announce("af_popup.STATUS_EXITING_POPUP");
1172
1173 var page = AdfPage.PAGE;
1174 var domElement = this.getContent();
1175
1176 // Set/remove these attributes for all screen reader mode popups, regardless of
1177 // hasSpecialRenderingForScreenReader being true or false
1178 if (AdfPage.PAGE.isScreenReaderMode())
1179 this.removeAccessibleAttrs();
1180
1181 this.SaveScrollValues(domElement);
1182
1183 // Must remove/unregister from the auto dismiss manager before restoring focus
1184 // because changing focus can cause the dismissal to hide the popup.
1185 // Depending on the browser, the dismissal hide (call to same method) might be
1186 // invoked before this method is completed causing a synchronization issue with the
1187 // AdfDhtmlZOrderManager (removing twice).
1188 var component = page.findComponent(this._componentId);
1189 var popupId = AdfDhtmlPopupWindow._getInternalPopupId(this, component);
1190 page.getAutoDismissalManager().removeBehavior(component, popupId);
1191
1192 // If the focus is currently in the popup, we need to restore the focus
1193 // to its previous location before we hide the popup. Note that before
1194 // restoring the focus, we also check to see whether there is a focus
1195 // change pending. This will be true if the app (or peer) attempts
1196 // to move the focus just before dismissing the popup. When this happens,
1197 // we want to honor the app/peer's focus change, so we avoid restoring the
1198 // focus.
1199
1200 // if canceled do to a dom replacement the the focus will be restored to the
1201 // last active dom element within the popup
1202 var isRestoring = this._isRestoring(component);
1203
1204 if (!isRestoring &&
1205 (page.getActiveDomElement() == null || AdfFocusUtils.containsFocus(this.getElement())) &&
1206 !AdfFocusUtils.isFocusChangePending())
1207 {
1208 // try/catch block added for bug 14676053 - return focus to flash object element
1209 try
1210 {
1211 this._restoreFocus();
1212 }
1213 catch (e)
1214 {
1215 AdfLogger.LOGGER.logErrorAsWarning(e, "restoring popup focus");
1216 }
1217 }
1218
1219 // unregister event handlers on the document and resizeListener on the content wraper
1220 //unregistering before calling closeHandler inorder to avoid any resize event triggers
1221 //while doing dom manipulation.
1222 this._unregisterEventHandlers();
1223 var isFullScreen = component.getProperty(AdfDhtmlPopupHints.POPUP_FULL_SCREEN);
1224 if(isFullScreen)
1225 {
1226 this._restoreZOrderLayerContainerSiblings();
1227 }
1228
1229 var isFullHeightPartialScreenPopup = component.getProperty(AdfDhtmlPopupHints.POPUP_FULL_HEIGHT_PARTIAL_SCREEN);
1230 var isPartialScreenPopup = component.getProperty(AdfDhtmlPopupHints.POPUP_PARTIAL_SCREEN);
1231 if(isPartialScreenPopup || isFullHeightPartialScreenPopup)
1232 {
1233 this._undoFixBodyPosition();
1234 }
1235
1236 var closeHandler = this._closeHandler;
1237 if (closeHandler)
1238 {
1239 delete this._closeHandler;
1240 closeHandler(this._closeHandlerParam);
1241 delete this._closeHandlerParam;
1242 }
1243
1244 this.destroy();
1245
1246 delete this._isHiding;
1247
1248 page.__perfTimings(false, false, true, "popup hidden: id=" + this._componentId);
1249}
1250
1251/**
1252 * @param {AdfDhtmlPopupWindow} popupWindow target popup controller to find id associating
1253 * with the component
1254 * @param {AdfUIComponent} component associated with this instance of the popup controller
1255 * @return {string} internal popupId or null
1256 */
1257AdfDhtmlPopupWindow._getInternalPopupId = function(popupWindow, component)
1258{
1259 if (component)
1260 {
1261 var peer = component.getPeer();
1262 if (peer)
1263 {
1264 var popupList = peer.getAllPopups(component);
1265 if (popupList)
1266 {
1267 for (popupId in popupList)
1268 {
1269 if (popupList[popupId] === popupWindow)
1270 return popupId;
1271 }
1272 }
1273 }
1274 }
1275
1276 return null;
1277}
1278
1279/**
1280 * Used to determine if the popup should restore focus when closed. If the popup is
1281 * canceled and needs to be restored, we don't need to restore focus prior to when the
1282 * popup was open.
1283 *
1284 * @param {AdfRichPopup} component popup component
1285 * @return {boolean} true if the component is a {@link AdfRichPopup}, property autoCancel
1286 * is disabled, and the popup was canceled due to a dom replacement.
1287 */
1288AdfDhtmlPopupWindow.prototype._isRestoring = function(component)
1289{
1290 var isRestoring = false;
1291 if (component instanceof AdfRichPopup &&
1292 component.getAutoCancel() == AdfRichPopup.AUTO_CANCEL_DISABLED)
1293 {
1294 var key = AdfDhtmlPopupWindow._createFocusPagePropertyKey(component.getClientId());
1295 var activeDomElementId = page.getPageProperty(key);
1296 isRestoring = (activeDomElementId ? true : false);
1297 }
1298 return isRestoring;
1299}
1300
1301/**
1302 * Dismisses the floating element indicating an awkward state or unexpected state.
1303 * @param {boolean} replaceDom optional flag that indicates the popup was canceled
1304 * due to a dom replacement of its markup.
1305 * @override
1306 */
1307AdfDhtmlPopupWindow.prototype.cancel = function(replaceDom)
1308{
1309 // locate the closed handler parameter so that we can add
1310 // and expando property on the content dom to indicate the
1311 // popup was hidden unexpectedly
1312
1313 var agent = AdfAgent.AGENT;
1314 var closeHandlerParam = this._closeHandlerParam;
1315 var contentDom = closeHandlerParam.contentDom;
1316 agent.setExpandoProperty(contentDom, AdfDhtmlPopupWindow.__CANCELED_EXPANDO, true);
1317 agent.setExpandoProperty(contentDom, AdfDhtmlPopupWindow.__REPLACEDOM_EXPANDO, (replaceDom ? true : false));
1318
1319 // Don't perform animation on canceling the popup. Animation is to be performed only on hide
1320 if (this._closingAnimationHints && replaceDom)
1321 {
1322 this._closingAnimationHints[AdfDhtmlPopupWindow.HINT_ANIMATE] = AdfRichPopup.ANIMATE_FALSE;
1323 }
1324
1325 if (this._isHiding)
1326 {
1327 if (this._animator && replaceDom)
1328 {
1329 this._animator.stop();
1330 var wrapper = this.getElement().parentNode;
1331 AdfDhtmlPopupWindow.CloseAnimationComplete({wrapper:wrapper, myself:this});
1332 }
1333 return;
1334 }
1335
1336 // If the focus is currently in the popup, we need to restore the focus
1337 // to its previous location before we hide the popup. See #hide
1338 if (replaceDom &&
1339 AdfFocusUtils.containsFocus(this.getElement()))
1340 {
1341 var poppupId = this.getPopupClientId();
1342 var key = AdfDhtmlPopupWindow._createFocusPagePropertyKey(poppupId);
1343 var page = AdfPage.PAGE;
1344 var activeDomElement = page.getActiveDomElement();
1345 if (activeDomElement && activeDomElement.id)
1346 page.setPageProperty(key, activeDomElement.id);
1347 }
1348
1349 AdfDhtmlPopupWindow.superclass.cancel.call(this);
1350}
1351
1352/**
1353 * Generates a key based on the popup's client id by replacing all ":" char's with "$"
1354 * and then adding a sufix of "$restoreFocus". The returned key is passed to
1355 * {@link AdfDhtmlPage#setPageProperty} and {@link AdfDhtmlPage#getPageProperty}.
1356 * This value pair will hold the last active dom element before the popup was
1357 * cancled due to a dom replacement.
1358 *
1359 * @param {String} clientId of the popup component
1360 * @return {String} map safe key
1361 */
1362AdfDhtmlPopupWindow._createFocusPagePropertyKey = function(clientId)
1363{
1364 AdfAssert.assertString(clientId);
1365 var tokens = clientId.split(":");
1366 return tokens.join("$") + "$restoreFocus";
1367}
1368
1369/**
1370 * Restore the keyboard focus to its previous location
1371 */
1372AdfDhtmlPopupWindow.prototype._restoreFocus = function()
1373{
1374 // Currently we try to restore the focus first to the align element
1375 // (if we have an align element) and then to the element which previously
1376 // had the focus. This simple strategy works just fine in the common
1377 // cases where the element which triggers the popup launch is still present
1378 // when the popup is dismissed. However, this does not handle the less
1379 // common case where the element which triggers the popup is no longer
1380 // present when the popup is dismissed.
1381 //
1382 // An example of this less common case is nested popups, where the parent
1383 // popup is dismissed when the child popup is launched. In this case,
1384 // the child popup may attempt to restore the focus to the launch element in
1385 // the parent popup, which will fail since the parent popup is no longer
1386 // visible. In this case, the child popup should attempt to restore
1387 // the focus to the element which triggered the parent popup launch. However,
1388 // currently if we fail to find an element to restore the focus to, we
1389 // lame out and move the focus to the first visible tab stop in the page.
1390 //
1391 // The nested popup scenario comes up in inputComboboxListOfValues, where
1392 // we've got a popup used for the combobox drop-down list which subsequently
1393 // launches the Search dialog. At the time the Search dialog is launched,
1394 // the focus in in the drop-down popup. This popup is immediately dismissed,
1395 // which means that the Search dialog cannot restore the focus. Ideally in
1396 // this case the Search dialog should instead restore the focus to the
1397 // element which launched its parent - ie. all the way back to the input field.
1398
1399 // TODO aschwart
1400 // 1. Fix the nested popup case where parent is dismissed when child is launched.
1401 // 2. Try harder to find a suitable element to restore the focus to when
1402 // the element that we want to restore the focus to is no longer available.
1403 // For example, we may be able to find a suitable sibling which can take
1404 // the focus, which would be an improvement over using the body.
1405
1406 // REMOVED workaround for bug 7694024; In IE, if a textarea is in the content of the popup,
1407 // This code would not get reached due to the above delay for IE
1408
1409
1410 // Bug 13699927 - weird focus issues on ie when closing non-modal popup
1411 // IE doesn't like the focus getting changed during mouseDown event processing that
1412 // causes autodismissal to occur. If we make a focus change during mouseDown event handling, IE will
1413 // fire a focus event on the form. This fix makes IE behave like other browsers by getting the target
1414 // of the mouseDown and if it is focusable, overriding the restoreFocus logic to set the restoreFocusElement to be
1415 // the srcElement of the mouseDown event. Actual setting of the focus is delayed in IE so this focus can occur after
1416 // IE sets focus on the form element.
1417
1418 var agent = AdfAgent.AGENT;
1419 var page = AdfPage.PAGE;
1420 var focusContextCache = new Object();
1421 // Try to find a suitable focus element in this order:
1422 // *) (IE Mouse Event ONLY) event target
1423 // 1) alignElement
1424 // 2) restoreFocusId (if focusable)
1425 // 3) launchSourceElement
1426 // 4) restoreFocusId next tabstop (for non-focusable restoreFocusId)
1427 var restoreFocusElement;
1428 var element = this.getElement();
1429 if(agent.getPlatform() == AdfAgent.IE_PLATFORM)
1430 {
1431 // bug 13699927
1432 // dialogs don't cancel auto dismiss when you click outside their content
1433 // This logic is only for autodismissal of non-dialogs.
1434 var isaDialog = (this instanceof AdfDhtmlSimpleFloat);
1435 if (!isaDialog)
1436 {
1437 var event = page.getDomWindow().event;
1438 if(event && event.type.indexOf("mouse") !== -1)
1439 {
1440 var eventTarget = agent.getEventTarget(event);
1441 if(eventTarget && AdfFocusUtils.isFocusable(eventTarget) &&
1442 !AdfDomUtils.isAncestorOrSelf(element, eventTarget))
1443 {
1444 restoreFocusElement = eventTarget;
1445 }
1446 }
1447 }
1448 }
1449
1450 if(!restoreFocusElement)
1451 {
1452 restoreFocusElement = this.getAlignElement();
1453 }
1454
1455 AdfLogger.LOGGER.fine("In AdfDhtmlPopupWindow#_restoreFocus(), _restoreFocusId set to " + this._restoreFocusId);
1456
1457 if( this._restoreFocusId &&
1458 (!restoreFocusElement ||
1459 !AdfFocusUtils.isFocusable(restoreFocusElement, focusContextCache)))
1460 {
1461 restoreFocusElement = page.getDomDocument().getElementById(this._restoreFocusId);
1462 }
1463
1464 // If restoreFocusElement is not focusable, favor the launchSourceId over _restoreFocusId.
1465 if( !restoreFocusElement || !AdfFocusUtils.isFocusable(restoreFocusElement, focusContextCache) )
1466 {
1467 var launchSourceElement = this.GetLaunchSourceElement();
1468 if (launchSourceElement)
1469 {
1470 restoreFocusElement = launchSourceElement;
1471 }
1472 }
1473
1474 // After the above logic, we should have a restoreFocusElement, if not, we are done
1475 if(restoreFocusElement)
1476 {
1477 if(agent.getPlatform() == AdfAgent.IE_PLATFORM && !this.isScreenReaderModePopup())
1478 {
1479 // Create a callback for IE so that the focus is fired outside of the autodismissal mouseDown event handling
1480 // This workaround isn't needed when in screen reader mode (and would causes other focus issues).
1481 var focusParams = new Object();
1482 focusParams["focusElement"] = restoreFocusElement;
1483 focusParams["popupElement"] = element;
1484 page.scheduleTimer(this, this._delayedCheckedFocus, focusParams, 10, {'isSynchronized' : true});
1485 return;
1486 }
1487 else if(AdfFocusUtils.isFocusable(restoreFocusElement, focusContextCache))
1488 {
1489 AdfFocusUtils.focusElement(restoreFocusElement);
1490 return;
1491 }
1492 // if the launcher component exists but is not a tabstop,
1493 // (context menu on an outputText) look for the next tabstop.
1494 AdfFocusUtils.focusNextTabStop(restoreFocusElement);
1495 return;
1496 }
1497
1498 // Sigh, no luck. For the moment, just set the focus to the
1499 // first tab stop in the document (skipping skipLink if present)...
1500 AdfFocusUtils.focusFirstDocumentTabStop();
1501}
1502
1503/**
1504 * Callback for setting focus with a check to see if the element is focusable
1505 * and the focus element is outside of the popup element, and there is not currently
1506 * a focusasble element in focus. (IE focus behavior fix)
1507 */
1508AdfDhtmlPopupWindow.prototype._delayedCheckedFocus = function(params)
1509{
1510 var popupElement = params["popupElement"];
1511 var focusElement = params["focusElement"];
1512 if ( !AdfFocusUtils.isFocusable(AdfPage.PAGE.getActiveDomElement()) &&
1513 !AdfDomUtils.isAncestorOrSelf(popupElement, focusElement) )
1514 {
1515 // Restore focus to the focusElement, or the next tabstop if its not focusable.
1516 (AdfFocusUtils.isFocusable(focusElement)) ? AdfFocusUtils.focusElement(focusElement) :
1517 AdfFocusUtils.focusNextTabStop(focusElement);
1518 }
1519}
1520
1521/**
1522 * Get the launch source element (if available). May return null. This is a protected method
1523 * and may be overwritten by child classes (AdfDhtmlPopupMenu.js).
1524 */
1525AdfDhtmlPopupWindow.prototype.GetLaunchSourceElement = function()
1526{
1527 var launchSourceId = this._launchSourceId;
1528 return (launchSourceId) ? AdfAgent.AGENT.getElementById(launchSourceId) : null;
1529}
1530
1531/**
1532 * Sets the content of this popup window.
1533 * @param {HTMLElement} selectorContent the dom element that is the content of the popupwindow
1534 */
1535AdfDhtmlPopupWindow.prototype.setContent = function(selectorContent)
1536{
1537 var contentElement = this.GetContentParent();
1538 if (contentElement.firstChild)
1539 contentElement.removeChild(contentElement.firstChild);
1540 contentElement.appendChild(selectorContent);
1541}
1542
1543/**
1544 * Sets accessibility attributes for the container element
1545 * @param {Object:null} hints a set of popup hints (see AdfDhtmlPopupWindow)
1546 */
1547AdfDhtmlPopupWindow.prototype.setAccessibleAttrs = function(hints)
1548{
1549 // Override me
1550}
1551
1552/**
1553 * Unsets accessible attributes to the popup container element.
1554 */
1555AdfDhtmlPopupWindow.prototype.removeAccessibleAttrs = function()
1556{
1557 // Override me
1558}
1559
1560/**
1561 * Announce opening of the popup via the wai-aria live region. To be overriden by children.
1562 * @param {Object:null} hints a set of popup hints
1563 */
1564AdfDhtmlPopupWindow.prototype.announceOpeningViaLiveRegion = function(hints)
1565{
1566 // Override me
1567}
1568
1569/**
1570 * @return {HTMLElement} returns the dom element that is the content of this popup window
1571 */
1572AdfDhtmlPopupWindow.prototype.getContent = function()
1573{
1574 return this.GetContentParent().firstChild;
1575}
1576
1577/**
1578 * Gets the dom element that is the parent of the popup's content.
1579 * Subclasses must override this method
1580 * @return {HTMLElement} contentParentElement the parent of the content
1581 */
1582AdfDhtmlPopupWindow.prototype.GetContentParent = function()
1583{
1584 AdfAssert.failedInAbstractFunction();
1585}
1586
1587
1588/**
1589* Sets the Handler invoked when the selector is being dismissed
1590* @param {Function} handler callback
1591*/
1592AdfDhtmlPopupWindow.prototype.setCloseHandler = function(handler)
1593{
1594 this._closeHandler = handler;
1595}
1596
1597
1598/**
1599* Sets the parameter for the Handler invoked when the selector is being dismissed
1600* @param {Object} actual arguments to the close handler
1601* @see #setCloseHandler
1602*/
1603AdfDhtmlPopupWindow.prototype.setCloseHandlerParam = function(param)
1604{
1605 this._closeHandlerParam = param;
1606}
1607
1608/**
1609 * @return {Boolean} indicates the visual state of the selector
1610 */
1611AdfDhtmlPopupWindow.prototype.isVisible = function()
1612{
1613 return this.getElement().style.display != "none";
1614}
1615
1616/**
1617 * Do the work to actually display of the popup window.
1618 * @param {Object:null} hints a set of popup hints (see {@link AdfDhtmlPopupWindow})
1619 */
1620AdfDhtmlPopupWindow.prototype.DoShow = function(hints)
1621{
1622 AdfDhtmlPopupWindow.superclass.show.call(this);
1623
1624 if (this.hasSpecialRenderingForScreenReader() && !this.GetFocusOnOpen())
1625 return;
1626
1627 this.raiseToFront();
1628 if(hints[AdfDhtmlPopupHints.POPUP_FULL_SCREEN])
1629 this._hideZOrderLayerContainerSiblings(hints);
1630}
1631
1632/**
1633 * Creates the shadow for this popup window.
1634 * @param {Boolean} afterAnimation flag indicates that we want to create the shadow after animation
1635 */
1636AdfDhtmlPopupWindow.prototype.CreateShadow = function(afterAnimation)
1637{
1638 // Do not create a shadow if we are animating. We will create the shadow later
1639 if(this.HasShadow() && (!this._animationDuration || afterAnimation))
1640 {
1641 AdfDhtmlShadowDecorator.createShadowDecorator(this.getShadowAnchor(), this.getElement().parentNode);
1642 }
1643}
1644
1645/**
1646 * @return whether or not the popup will have a shadow
1647 */
1648AdfDhtmlPopupWindow.prototype.HasShadow = function()
1649{
1650 return true;
1651}
1652
1653/**
1654 * @return {Boolean} always returns true indicating the position manager should invert the primary position
1655 * if can't be aligned to the primary align hint.
1656 */
1657AdfDhtmlPopupWindow.prototype.shouldInvertPosition= function()
1658{
1659 return true;
1660}
1661
1662/**
1663 * Unregister event handlers, remove the shadow decorator, unregister with
1664 * the position manager before calling on super.
1665 * @override
1666 */
1667AdfDhtmlPopupWindow.prototype.destroy = function()
1668{
1669 var agent = AdfAgent.AGENT;
1670 var page = AdfPage.PAGE;
1671
1672 // after the content has be re-parented by the close handler, unregister the
1673 // dynamic elements - registered id for the resizeListener. @see #WrapContent
1674 agent.elementsRemoved(this.getElement());
1675
1676 this._restoreFocusElement = null;
1677
1678 if(this._sizeTimeout != null)
1679 {
1680 page.cancelTimer(this._sizeTimeout);
1681 delete this._sizeTimeout;
1682 }
1683
1684 var shadowAnchor = this.getShadowAnchor();
1685 if (AdfDhtmlShadowDecorator.hasShadowDecorator(shadowAnchor))
1686 {
1687 AdfDhtmlShadowDecorator.removeShadowDecorator(shadowAnchor);
1688 }
1689 if(this._positionManagerIndex != null)
1690 page.getPositionManager().removeElement(this._positionManagerIndex);
1691
1692 this.setAlignElement(null);
1693
1694 AdfDhtmlPopupWindow.superclass.destroy.call(this);
1695}
1696
1697/**
1698 * Returns if the popup window is currently animating during the opening of the window.
1699 * @return true if the popup is currently animating during opening else false.
1700 */
1701AdfDhtmlPopupWindow.prototype.isAnimating = function()
1702{
1703 return this._animator != null || this._isOpening
1704}
1705
1706/**
1707 * @return {Number} numeric token used by the position manager service to track a registed
1708 * floating element.
1709 */
1710AdfDhtmlPopupWindow.prototype.GetPositionManagerIndex = function()
1711{
1712 return this._positionManagerIndex;
1713}
1714
1715/**
1716 * Handles the keydown event from the document. The _registerEventHanders and
1717 * _unregisterEventHandlers functions manage registration and called from the
1718 * show and hide functions.
1719 *
1720 * Intercepts the tab key press to cycle focus within the floating element. If focus
1721 * is on the last element, focus returns to the first tab-able element in the popup.
1722 *
1723 * @param {Event} event
1724 */
1725AdfDhtmlPopupWindow.prototype._handleKeyDown = function(event)
1726{
1727 var agent = AdfAgent.AGENT;
1728 var targetElement = agent.getEventTarget(event);
1729 var popupContainer = this.getElement();
1730 if (event.keyCode == AdfKeyStroke.TAB_KEY)
1731 {
1732 var firstFocusableElementInPopup = AdfFocusUtils.getFirstTabStop(popupContainer);
1733 var lastElement = AdfFocusUtils.getLastTabStop(popupContainer);
1734
1735 // If the popup doesn't contain any focusable content, ignore and eat the tab keyDown event.
1736 if (firstFocusableElementInPopup == null)
1737 {
1738 agent.eatEvent(event);
1739 return;
1740 }
1741
1742 if (event.shiftKey)
1743 {
1744 if (targetElement == firstFocusableElementInPopup)
1745 {
1746 AdfFocusUtils.focusPreviousTabStop(targetElement, popupContainer);
1747 agent.eatEvent(event);
1748 }
1749 }
1750 else
1751 {
1752 if (lastElement == targetElement)
1753 {
1754 AdfFocusUtils.focusNextTabStop(targetElement, popupContainer);
1755 agent.eatEvent(event);
1756 }
1757 }
1758 }
1759 else if (event.keyCode == AdfKeyStroke.F6_KEY)
1760 {
1761 if (AdfPage.PAGE.isScreenReaderMode() &&
1762 !this.hasSpecialRenderingForScreenReader() &&
1763 AdfDomUtils.isAncestorOrSelf(popupContainer, targetElement))
1764 {
1765 // F6 is for focus management on popup in accessibility mode
1766 this.HandleKeyNavigation(event);
1767 }
1768 }
1769}
1770
1771/**
1772 * Handles the keyup event from the document. The _registerEventHanders and
1773 * _unregisterEventHandlers functions manage registration and called from the
1774 * show and hide functions.
1775 *
1776 * The ESC key is handled if the HINT_CLOSE_ON_ESCAPE hint was turned on. This logic will
1777 * hide the floating element if the event target is within the popup. Or, if the
1778 * HINT_LAUNCH_SOURCE_ID hint is provided, the dom element it points to is considered within
1779 * the popup.
1780 *
1781 * @see #HandleEscapeKey
1782 *
1783 * @param {Event} keyup event
1784 */
1785AdfDhtmlPopupWindow.prototype._handleKeyUp = function(event)
1786{
1787 var agent = AdfAgent.AGENT;
1788 var keyCode = agent.getKeyCode(event);
1789 var targetElement = agent.getEventTarget(event);
1790
1791 if (keyCode == AdfKeyStroke.ESC_KEY)
1792 {
1793 // was HINT_CLOSE_ON_ESCAPE hint provided
1794 if(this._closeOnEscape)
1795 {
1796 var invokeEscapeHandler = false;
1797
1798 // was HINT_LAUNCH_SOURCE_ID hint provided
1799 var launchSourceId = this._launchSourceId;
1800
1801 if (AdfDomUtils.isAncestorOrSelf(this.getElement(), targetElement))
1802 {
1803 invokeEscapeHandler = true;
1804 }
1805 else if (launchSourceId)
1806 {
1807 var launchElement = agent.getElementById(launchSourceId);
1808 if (launchElement && AdfDomUtils.isAncestorOrSelf(launchElement, targetElement))
1809 {
1810 invokeEscapeHandler = true;
1811 }
1812 }
1813 if (invokeEscapeHandler)
1814 {
1815 this.HandleEscapeKey(event);
1816 }
1817 }
1818 }
1819
1820 if ((event.ctrlKey) && (event.altKey) && (keyCode == AdfKeyStroke.W_KEY))
1821 {
1822 if (AdfDomUtils.isAncestorOrSelf(this.getElement(), targetElement))
1823 {
1824 this.HandleKeyNavigation(event);
1825 }
1826 }
1827}
1828
1829/**
1830 * Overridable function to handle escape key.
1831 *
1832 * @param {Event} key up event
1833 */
1834AdfDhtmlPopupWindow.prototype.HandleEscapeKey = function(event)
1835{
1836 this.cancel();
1837 AdfAgent.AGENT.eatEvent(event);
1838}
1839
1840/**
1841 * Overridable function to move focus away from the popup
1842 *
1843 * @param {Event} key up event
1844 */
1845AdfDhtmlPopupWindow.prototype.HandleKeyNavigation = function(event)
1846{
1847}
1848
1849/**
1850 * Sizes the popup window and then validate the position with the position manager service.
1851 * If animation is enabled, animate the window sizing from the alignment computed
1852 * by the position manager.
1853 * @param {Object:null} hints a set of popup hints (see {@link AdfDhtmlPopupWindow})
1854 */
1855AdfDhtmlPopupWindow.prototype._size = function(hints)
1856{
1857 if(this._sizeTimeout == null)
1858 return;
1859
1860 delete this._sizeTimeout;
1861
1862 //Finalize the size of components inside popup and then validate the popup's position
1863 var domElement = this.getContent();
1864 this.DoResizeNotifyDom(domElement);
1865
1866 // We hard-set the width of the table. If we do not do this, the table will
1867 // try to wrap it's content after resizing. We won't get any notifications
1868 // of that. This causes weird behavior. For example, shadowDecorators are
1869 // not updated and out of sync with the element.
1870 var element = this.getElement(), elementStyle = element.style;
1871
1872 // Look to see if here was a popup hint, maximum width, provided.
1873 // The private attribute is assigned in the show method using
1874 // the AdfDhtmlPopupWindow.HINT_MAX_WIDTH hint. By default, the popup
1875 // will not have a maximum width. The content will determine the size.
1876
1877 var maxWidth = this._maxWidth;
1878 if (maxWidth)
1879 {
1880 // if there is a hints override, use the lesser of what the browser needs
1881 // or the popup max-width hint
1882 elementStyle.width = Math.min(element.offsetWidth, maxWidth) +"px";
1883 }
1884 else
1885 {
1886 // explicitly set the width to what the browser thinks it needs
1887 elementStyle.width = element.offsetWidth +"px";
1888 }
1889 if(hints[AdfDhtmlPopupHints.POPUP_FULL_SCREEN])
1890 {
1891 elementStyle.maxHeight= AdfPage.PAGE.getDomWindow().innerHeight +"px";
1892 elementStyle.height = AdfPage.PAGE.getDomWindow().innerHeight +"px";
1893 }
1894
1895 // if registered with the position manager, compute the alignment
1896 if(this._positionManagerIndex != null)
1897 {
1898 // compute the center position of the pop up after it is sized.
1899 var screenCenterPosition = hints[AdfDhtmlPopupWindow.HINT_POSITION_CENTER];
1900 if (screenCenterPosition)
1901 {
1902 this.setAlignPosition(this.CalcAlignPosition());
1903 }
1904 AdfPage.PAGE.getPositionManager().validatePosition(this._positionManagerIndex);
1905 }
1906
1907 if (this.hasSpecialRenderingForScreenReader() && !this.GetFocusOnOpen())
1908 AdfPopupScopingUtils.scope(AdfPage.PAGE.getActiveDomElement());
1909
1910 // if animation is turned on, animate opening from the alignment position
1911 var animationDuration = this.GetAnimationDuration();
1912 if(animationDuration > 0)
1913 {
1914 this.AnimateOpening(hints);
1915 }
1916 else
1917 {
1918 // actually display the element
1919 elementStyle.visibility = "";
1920
1921 // create the shadow decorator
1922 this.CreateShadow();
1923
1924 // Invoke the popup opened callback handler. It's only invoked the first
1925 // time the resizing occurs.
1926 this.OpenedPopup(hints);
1927 }
1928}
1929
1930/**
1931 * Animates the opening of the popup.
1932 *
1933 * @see #GetAnimationDuration
1934 * @param {Object:null} hints a set of popup hints (see {@link AdfDhtmlPopupWindow})
1935 */
1936AdfDhtmlPopupWindow.prototype.AnimateOpening = function(hints)
1937{
1938 var launchSourceId = this._launchSourceId;
1939
1940 this.AnimateUsingWrapper(this.GetAnimationDuration(), hints, true);
1941}
1942
1943/**
1944 * To get popup anchors isRight and isBottom properties.
1945 */
1946AdfDhtmlPopupWindow.prototype._getAnchorProperties = function()
1947{
1948 var anchor = new Object;
1949 anchor.isRight = false;
1950 anchor.isBottom = false;
1951
1952 var positionManagerIndex = this.GetPositionManagerIndex();
1953
1954 if(positionManagerIndex >=0)
1955 {
1956 var behavior = AdfPage.PAGE.getPositionManager().getComputedBehavior(positionManagerIndex);
1957
1958 if (behavior)
1959 {
1960 anchor.isRight = behavior.horizontalBehavior.floatingElementAnchor == AdfDhtmlPositionManager.RIGHT;
1961 anchor.isBottom = behavior.verticalBehavior.floatingElementAnchor == AdfDhtmlPositionManager.BOTTOM;
1962 }
1963 }
1964
1965 return anchor;
1966}
1967
1968/**
1969 * To show animation while closing the popup.
1970 */
1971AdfDhtmlPopupWindow.prototype.AnimateClosing = function(hints)
1972{
1973 this.AnimateUsingWrapper(this.GetCloseAnimationDuration(), hints, false);
1974}
1975
1976/**
1977 * Removes the managed dom element replacing with a hidden div. The current coordinates are
1978 * captured and used as the finals for the animation.
1979 *
1980 * @param {Number} animationDuration elapsed time the opening animation should take. Configured per
1981 * component as a skinning property.
1982 * @param {Object} anchor.isRight aligment is anchored on the right edge of the dialog and
1983 * anchor.isBottom alignment is anchored on the buttom edge of the dialog
1984 * @param {Object:null} hints a set of popup hints (see {@link AdfDhtmlPopupWindow})
1985 */
1986AdfDhtmlPopupWindow.prototype.AnimateUsingWrapper = function(
1987 animationDuration,
1988 hints,
1989 isOpening)
1990{
1991 var rootElement = this.getElement();
1992
1993 // get the dom position style of root element
1994 var styleProperties = AdfDhtmlPopupWindow._getElementStyle(rootElement);
1995
1996 // create the wrapper to show animation on UI
1997 var wrapper = AdfDhtmlPopupWindow._createTransitionWrapper(rootElement);
1998
1999 var transitionProperties = AdfDhtmlPopupWindow._setUpWrapperTransition(rootElement, wrapper, hints, isOpening,
2000 styleProperties, this._getAnchorProperties());
2001 if (transitionProperties != null)
2002 {
2003 if (isOpening)
2004 {
2005 // save the scrollTop's so they can be restored back later
2006 this.SaveScrollValues(rootElement);
2007 }
2008
2009 rootElement.parentNode.replaceChild(wrapper, rootElement);
2010 wrapper.appendChild(rootElement);
2011
2012 if (isOpening)
2013 {
2014 // Before animating, make sure that there is a maskingFrame available to avoid potential iframe
2015 // creation at the end of the animation. (bug 7137710)
2016 AdfPage.PAGE.prepareMaskingFrame(rootElement);
2017 }
2018
2019 this._animator = AdfDhtmlElementAnimator.animate(
2020 AdfDhtmlElementAnimator.FRAME_METHOD_CONSTANT_SPEED,
2021 animationDuration,
2022 [
2023 {
2024 "element": wrapper,
2025 "properties" :transitionProperties
2026 }
2027 ],
2028 null,
2029 isOpening ? AdfDhtmlPopupWindow.OpenAnimationComplete : AdfDhtmlPopupWindow.CloseAnimationComplete,
2030 {"wrapper" :wrapper, "myself": this, "hints": hints});
2031 }
2032 else
2033 {
2034 if (isOpening)
2035 {
2036 // actually display the popup
2037 rootElement.style.visibility = "";
2038
2039 // create the shadow decorator for popup
2040 this.CreateShadow();
2041
2042 this.OpenedPopup(hints);
2043 }
2044 else
2045 {
2046 this.ClosedPopup();
2047 }
2048 }
2049}
2050
2051/**
2052 * To get the DOM position styles
2053 */
2054AdfDhtmlPopupWindow._getElementStyle = function (element)
2055{
2056 var elementStyle = {};
2057
2058 elementStyle.height = element.offsetHeight;
2059 elementStyle.width = element.offsetWidth;
2060 elementStyle.top = parseInt(element.style.top);
2061 elementStyle.left = parseInt(element.style.left);
2062 elementStyle.right = elementStyle.left + elementStyle.width;
2063
2064 return elementStyle;
2065}
2066
2067/**
2068 * To create popups wrapper div to show animation.
2069 */
2070AdfDhtmlPopupWindow._createTransitionWrapper = function (rootElement)
2071{
2072 var ownerDoc = rootElement.ownerDocument;
2073
2074 var wrapper = ownerDoc.createElement("div");
2075
2076 wrapper.setAttribute(AdfDhtmlPopupWindow._ANIMATE_WRAPPER_EXPANDO, true);
2077 wrapper.style.overflow = "hidden";
2078 wrapper.style.position = "absolute";
2079 wrapper.style.zIndex = rootElement.style.zIndex;
2080
2081 return wrapper;
2082}
2083
2084/**
2085 * To set wrapper transition related styles and return properties for animation.
2086 */
2087AdfDhtmlPopupWindow._setUpWrapperTransition = function (rootElement, wrapper, hints, isOpening,
2088 styleProperties, anchor)
2089{
2090 // To hold, is it for opening or closing popup
2091 var transition = isOpening ?
2092 hints[AdfDhtmlPopupHints.OPEN_TRANSITION] : hints[AdfDhtmlPopupHints.CLOSE_TRANSITION];
2093
2094 if (isOpening && (!transition || transition == AdfDhtmlPopupHints.TRANSITION_AUTO))
2095 {
2096 // While opening popup, if animation is enabled and af:transition is configured to "auto"
2097 // or af:transition is not configured for triggerType="open". Its default behavior.
2098 return AdfDhtmlPopupWindow._growTransition(rootElement, wrapper, styleProperties, anchor);
2099 }
2100 else if (transition == AdfDhtmlPopupHints.TRANSITION_VERTICAL ||
2101 transition == AdfDhtmlPopupHints.TRANSITION_HORIZONTAL)
2102 {
2103 // If transition is vertical or horizontal, it means sliding animation.
2104 return AdfDhtmlPopupWindow._slideTransition(rootElement, wrapper, styleProperties, isOpening, transition,
2105 anchor);
2106 }
2107
2108 // If af:transition is configured to "none", or configured unsupported transition type.
2109 return null;
2110}
2111
2112/**
2113 * This is default behavior to show popup animation as growing diagonally. The diagonal growing direction will be based
2114 * on two parameters, i.e. anchor.isRight, anchor.isBottom. The actual popup, rootElemnt, will not resize or animate,
2115 * it will float in the wrapper element. The root popup element will stick to two of the wrapper div edges, based on
2116 * anchor.isRight and anchor.isBottom values. Doing so, the root element will be positioned along with wrapper elements.
2117 * The approach is, first set the root element position styles, then initial wrapper animation properties, from where
2118 * animation will start, and at last compute animation properties, where wrapper animation will end.
2119 *
2120 * return properties, will be used by AdfDhtmlElementAnimator.animate() to make sliding frams, to show animation.
2121 */
2122AdfDhtmlPopupWindow._growTransition = function (rootElement, wrapper, styleProperties, anchor)
2123{
2124 // to set root element at top left in wrapper.
2125 var rootStyle = rootElement.style;
2126 rootStyle.top = "0px";
2127 rootStyle.left = "0px";
2128
2129 // To start animation from 1 X 1 px, set wrapper height and width.
2130 var wrapperStyle = wrapper.style;
2131 wrapperStyle.height = "1px";
2132 wrapperStyle.width = "1px";
2133
2134 // Both height and width needs to grow while showing animation
2135 var properties = { "height" : styleProperties.height,
2136 "width" : styleProperties.width};
2137
2138 if(anchor.isRight)
2139 {
2140 // If anchor is at right, then popup is at left side of aligned element,
2141 // It means we need to grow from right to left.
2142 wrapperStyle.left = (styleProperties.left + styleProperties.width - 1) + "px";
2143
2144 properties.left = styleProperties.left;
2145 }
2146 else
2147 {
2148 // If anchor is at left, then popup is at right side of aligned element,
2149 // It means we need to grow from left to right.
2150 wrapperStyle.left = styleProperties.left + "px";
2151 }
2152
2153 if(anchor.isBottom)
2154 {
2155 // If anchor is at bottom, then popup is at top side of aligned element,
2156 // It means we need to grow from bottom to top.
2157 wrapperStyle.top = (styleProperties.top + styleProperties.height +1) + "px";
2158
2159 properties.top = styleProperties.top;
2160 }
2161 else
2162 {
2163 // If anchor is at top, then popup is at bottom side of aligned element,
2164 // It means we need to grow from top to bottom.
2165 wrapperStyle.top = styleProperties.top + "px";
2166 }
2167
2168 // At the end make popup visible
2169 rootStyle.visibility = "";
2170
2171 return properties;
2172}
2173
2174/**
2175 * To set sliding animation on popup warpper.
2176 */
2177AdfDhtmlPopupWindow._slideTransition = function (rootElement, wrapper, styleProperties, isOpening, transition, anchor)
2178{
2179 var rootStyle = rootElement.style;
2180 var wrapperStyle = wrapper.style;
2181 var properties = {};
2182
2183 // get the sliding direction, Example slide towards left, right, up or down.
2184 var slideDirection = AdfDhtmlPopupWindow._getSlideDirection(isOpening, transition, anchor);
2185
2186 if (slideDirection == AdfDhtmlPopupWindow._SLIDE_LEFT || slideDirection == AdfDhtmlPopupWindow._SLIDE_RIGHT)
2187 {
2188 // If sliding direction is horizontal, slide left or right
2189 properties = AdfDhtmlPopupWindow._horizontalSlideTransition(rootStyle, wrapperStyle, styleProperties,
2190 isOpening, slideDirection);
2191 }
2192 else if (slideDirection == AdfDhtmlPopupWindow._SLIDE_UP || slideDirection == AdfDhtmlPopupWindow._SLIDE_DOWN)
2193 {
2194 // If sliding direction is vertical, slide up or down
2195 properties = AdfDhtmlPopupWindow._verticalSlideTransition(rootStyle, wrapperStyle, styleProperties,
2196 isOpening, slideDirection);
2197 }
2198
2199 rootStyle.visibility = "";
2200
2201 return properties;
2202}
2203
2204/**
2205 * To get sliding direction left, right, up or down. Sliding direction will be based on state of popup,
2206 * opening or closing, transition value and anchor position of popup.
2207 */
2208AdfDhtmlPopupWindow._getSlideDirection = function (isOpening, transition, anchor)
2209{
2210 // IF the transition is horizontal, then sliding would be left or right.
2211 // Else do sliding up or down.
2212 if (transition == AdfDhtmlPopupHints.TRANSITION_HORIZONTAL)
2213 {
2214 // If anchor is at right, it means popup is at left side of aligned element. So if anchor is at right,
2215 // and popup is opening, then do left sliding. Else do sliding towards right.
2216 if ((anchor.isRight && isOpening) || (!anchor.isRight && !isOpening))
2217 {
2218 return AdfDhtmlPopupWindow._SLIDE_LEFT;
2219 }
2220 else
2221 {
2222 return AdfDhtmlPopupWindow._SLIDE_RIGHT;
2223 }
2224 }
2225 else if (transition == AdfDhtmlPopupHints.TRANSITION_VERTICAL)
2226 {
2227 // If anchor is at bottom, it means popup is at top side of aligned element. So if anchor is at top,
2228 // and popup is opening, then do up sliding. Else do sliding towards down.
2229 if ((anchor.isBottom && isOpening) || (!anchor.isBottom && !isOpening))
2230 {
2231 return AdfDhtmlPopupWindow._SLIDE_UP;
2232 }
2233 else
2234 {
2235 return AdfDhtmlPopupWindow._SLIDE_DOWN;
2236 }
2237 }
2238}
2239
2240/**
2241 * To make horizontal sliding animation. The horizontal sliding direction will be based on two parameters,
2242 * i.e. isOpening, slideDirection. The actual popup, rootStyle, will not resize or animate, it will float in
2243 * the wrapper element. The root popup element will stick to two of the wrapper div edges, based on isOpening and
2244 * slideDirection values. Doing so, the root element will be positioned along with wrapper element sliding animation.
2245 * The approach is, first set the root element position, then set the initial wrapper animation properties,
2246 * from where animation will start, and compute animation properties, where wrapper animation will end.
2247 *
2248 * return properties, will be used by AdfDhtmlElementAnimator.animate() to make sliding frams, to show animation.
2249 */
2250AdfDhtmlPopupWindow._horizontalSlideTransition = function (rootStyle, wrapperStyle, styleProperties,
2251 isOpening, slideDirection)
2252{
2253 // Stick root popup to top side of wrapper.
2254 rootStyle.top = "0px";
2255
2256 wrapperStyle.top = styleProperties.top + "px";
2257 wrapperStyle.height = styleProperties.height + "px";
2258
2259 var properties = {};
2260
2261 if (isOpening) // Slide while opening popup
2262 {
2263 // start popup wrapper animation with width of 1px
2264 wrapperStyle.width = "1px";
2265
2266 // Animation will end at width of actual root popup width
2267 properties.width = styleProperties.width;
2268
2269 if (slideDirection == AdfDhtmlPopupWindow._SLIDE_LEFT) // slide left
2270 {
2271 // Stick root popup to wrappers left edge
2272 rootStyle.left = "0px";
2273
2274 // Start the animation from right side of popup
2275 wrapperStyle.left = (styleProperties.left + styleProperties.width - 1) + "px";
2276
2277 // Animation will end at left at actual root popup left.
2278 properties.left = styleProperties.left;
2279 }
2280 else // slide right
2281 {
2282 // Stick to right to wrappers right edge
2283 rootStyle.left = "auto";
2284 rootStyle.right = "0px";
2285
2286 wrapperStyle.left = styleProperties.left + "px";
2287 }
2288 }
2289 else // slide while closing the popup
2290 {
2291 // start animation from full width till 1px width
2292 wrapperStyle.width = styleProperties.width + "px";
2293 properties.width = 1;
2294
2295 if (slideDirection == AdfDhtmlPopupWindow._SLIDE_LEFT) // slide left
2296 {
2297 // stick root element to right side of wrapper edge
2298 rootStyle.left = "auto";
2299 rootStyle.right = "0px";
2300
2301 // Set wrapper left as left of root popup
2302 wrapperStyle.left = styleProperties.left + "px";
2303 }
2304 else // slide right
2305 {
2306 // Stick left side of root to the left edge of wrapper.
2307 rootStyle.left = "0px";
2308
2309 wrapperStyle.left = (styleProperties.left - 1) + "px";
2310
2311 // Animation will end at right side of rendered popup
2312 properties.left = (styleProperties.left + styleProperties.width - 1);
2313 }
2314 }
2315
2316 return properties;
2317}
2318
2319/**
2320 * To make vertical sliding animation. The vertical sliding direction will be based on two parameters, i.e. isOpening,
2321 * slideDirection. The actual popup, rootStyle, will not resize or animate, it will float in the wrapper element. The
2322 * root popup element will stick to two of the wrapper div edges, based on isOpening and slideDirection values. Doing
2323 * so, the root element will be positioned along with wrapper element sliding animation.The approach is, first set
2324 * the root element position, then set the initial wrapper animation properties, from where animation will start, and
2325 * compute animation properties, where wrapper animation will end.
2326 *
2327 * return properties, will be used by AdfDhtmlElementAnimator.animate() to make sliding frams, to show animation.
2328 */
2329AdfDhtmlPopupWindow._verticalSlideTransition = function (rootStyle, wrapperStyle, styleProperties,
2330 isOpening, slideDirection)
2331{
2332 // Stick root popup to left side of wrapper.
2333 rootStyle.left = "0px";
2334
2335 wrapperStyle.width = styleProperties.width + "px";
2336 wrapperStyle.left = styleProperties.left + "px";
2337
2338 var properties = {};
2339
2340 if (isOpening) // slide while opening popup
2341 {
2342 // start popup wrapper animation with height of 1px
2343 wrapperStyle.height = "1px";
2344
2345 // Animation will end at height and top of actual root popup height and top
2346 properties.top = styleProperties.top;
2347 properties.height = styleProperties.height;
2348
2349 if (slideDirection == AdfDhtmlPopupWindow._SLIDE_UP) // Slide upwards
2350 {
2351 // Stick root popup to wrappers top edge
2352 rootStyle.top = "0px";
2353
2354 // Start the animation from bottom side of popup
2355 wrapperStyle.top = (styleProperties.top + styleProperties.height - 1) + "px";
2356 }
2357 else // Slide downwards
2358 {
2359
2360 // Stick root to bottom of wrappers bottom edge
2361 rootStyle.top = "auto";
2362 rootStyle.bottom = "0px";
2363 rootStyle.height = styleProperties.height + "px";
2364
2365 wrapperStyle.top = (styleProperties.top + 1) + "px";
2366 }
2367 }
2368 else // slide while closing popup
2369 {
2370 // start animation from full height till 1px height
2371 wrapperStyle.height = styleProperties.height + "px";
2372 wrapperStyle.top = styleProperties.top + "px";
2373
2374 properties.height = 1;
2375
2376 if (slideDirection == AdfDhtmlPopupWindow._SLIDE_UP) // slide upwards
2377 {
2378 // stick root element to bottom side of wrapper edge
2379 rootStyle.top = "auto";
2380 rootStyle.bottom = "0px";
2381 }
2382 else // slide downwards
2383 {
2384 // Stick top side of root to the top edge of wrapper.
2385 rootStyle.top = "0px";
2386 rootStyle.height = styleProperties.height + "px";
2387
2388 // Set wrapper top as top of root popup
2389 wrapperStyle.top = styleProperties.top + "px";
2390
2391 // Animation will end at top side of rendered popup
2392 properties.top = styleProperties.top + styleProperties.height;
2393 }
2394 }
2395
2396 return properties;
2397}
2398
2399/**
2400 * Callback invoked after close animation has completed. Invokes the popup closing logic.
2401 *
2402 * @param {Object} context object holding the content element, hints and instance of this object
2403 */
2404AdfDhtmlPopupWindow.CloseAnimationComplete = function(context)
2405{
2406 var myself = context.myself;
2407 var wrapper = context.wrapper;
2408
2409 if (!myself._animator)
2410 return;
2411
2412 delete myself._animator;
2413
2414 AdfDhtmlPopupWindow._restoreRootPostAnimation(wrapper);
2415
2416 myself.ClosedPopup();
2417}
2418
2419
2420/**
2421 * Restores the dom element after animation has completed.
2422 * @param {Object} wrapper object holding the content element and instance of this object
2423 */
2424AdfDhtmlPopupWindow._restoreRootPostAnimation = function(wrapper)
2425{
2426 var wrapperStyle = wrapper.style;
2427 var rootElement = wrapper.firstChild;
2428 var rootStyle = rootElement.style;
2429
2430 rootStyle.right = wrapperStyle.right;
2431 rootStyle.left = wrapperStyle.left;
2432 rootStyle.top = wrapperStyle.top;
2433 wrapper.parentNode.replaceChild(rootElement, wrapper);
2434}
2435
2436/**
2437 * Callback invoked after open animation has completed. Restores the
2438 * dom element, creates the shadow decorator and then invokes the
2439 * popup opening logic.
2440 *
2441 * @see AdfDhtmlPopupWindow#_restoreRootPostAnimation
2442 * @see #CreateShadow
2443 * @see #OpenedPopup
2444 *
2445 * @param {Object} wrapper object holding the content element and instance of this object
2446 */
2447AdfDhtmlPopupWindow.OpenAnimationComplete = function(context)
2448{
2449 var wrapper = context.wrapper;
2450 var myself = context.myself;
2451 var hints = context.hints;
2452
2453 if (!myself._animator)
2454 return;
2455
2456 // see use of _animator in AdfDhtmlPopupLayer
2457 delete myself._animator;
2458
2459 AdfDhtmlPopupWindow._restoreRootPostAnimation(wrapper);
2460
2461 myself.CreateShadow(true);
2462
2463 myself.OpenedPopup(hints);
2464}
2465
2466/**
2467 * @return {Number} the duration of the animation for the popup
2468 */
2469AdfDhtmlPopupWindow.prototype.GetAnimationDuration = function()
2470{
2471 return this._animationDuration;
2472}
2473
2474/**
2475 *
2476 * @return {Number} the duration of the close animation for the popup
2477 * @Override
2478 */
2479AdfDhtmlPopupWindow.prototype.GetCloseAnimationDuration = function()
2480{
2481 return this._animationDuration;
2482}
2483
2484/**
2485 * @return {String} the skin property for animation duriation
2486 * @param {Object:null} hints a set of popup hints (see {@link AdfDhtmlPopupWindow})
2487 */
2488AdfDhtmlPopupWindow.prototype.GetAnimationDurationSkinProperty = function(hints)
2489{
2490 return null;
2491}
2492
2493/**
2494 * @return {String} the skin property for -tr-animate
2495 */
2496AdfDhtmlPopupWindow.prototype.GetAnimateSkinProperty = function()
2497{
2498 return null;
2499}
2500
2501
2502/**
2503 * Updates the size of the popup to match its content and resizes the shadow
2504 * decorator.
2505 */
2506AdfDhtmlPopupWindow.prototype.autoSize = function()
2507{
2508 var isOpening = this._isOpening;
2509
2510 if (!this.isVisible() || isOpening)
2511 {
2512 return;
2513 }
2514
2515 var element = this.getElement(), elementStyle = element.style;
2516
2517 // Look to see if here was a popup hint, maximum width, provided.
2518 // The private attribute is assigned in the show method using
2519 // the AdfDhtmlPopupWindow.HINT_MAX_WIDTH hint. By default, the popup
2520 // will not have a maximum width. The content will determine the size.
2521
2522 // Set the width temporarily to 'auto' so when we get the offset width, we are getting its true
2523 // value, and not just the value that was set earlier. Without setting width to auto here,
2524 // detachable menus with longer header names don't resize properly (bug 6507828).
2525 elementStyle.width = "auto";
2526
2527 var maxWidth = this._maxWidth;
2528 if (maxWidth)
2529 {
2530 // if there is a hints override, use the lesser of what the browser needs
2531 // or the popup max-width hint
2532 elementStyle.width = Math.min(element.offsetWidth, maxWidth) +"px";
2533 }
2534 else
2535 {
2536 // explicitly set the width to what the browser thinks it needs
2537 elementStyle.width = element.offsetWidth +"px";
2538 }
2539
2540 var anchor = this.getShadowAnchor();
2541 if (AdfDhtmlShadowDecorator.hasShadowDecorator(anchor))
2542 {
2543 AdfDhtmlShadowDecorator.moveShadowDecorator(anchor);
2544 AdfDhtmlShadowDecorator.showShadowDecorator(anchor, true);
2545 }
2546}
2547
2548
2549/**
2550 * Sets focus to the first content element in the window.
2551 *
2552 * @see #GetFocusContent
2553 */
2554AdfDhtmlPopupWindow.prototype.FocusOnFirstElement = function(force)
2555{
2556 // If we are animating we do not need to do any focus. The focus will be done post animation
2557 if (this._animator != null)
2558 return;
2559
2560 // if focus popup hint was not provided, don't try to set focus
2561 var focusHint = this.GetFocusOnOpen();
2562 if (!force && !(focusHint))
2563 {
2564 return;
2565 }
2566
2567
2568 // Only set focus on the container for IOS, since setting focus on an input field
2569 // causes weird issues with virtual keyboard etc
2570 var agent = AdfAgent.AGENT;
2571 var domWindow = agent.getDomWindow();
2572 var rootElement = this.getElement();
2573
2574 if (domWindow.AdfSafariMobileAgent && (agent instanceof AdfSafariMobileAgent) &&
2575 agent.getOS() != AdfAgent.ANDROID_OS)
2576 {
2577 rootElement.tabIndex = -1;
2578 AdfFocusUtils.focusElement(rootElement);
2579 return;
2580 }
2581
2582 //this.RestoreScrollValues(this.getContent());
2583
2584 // find the content area. this will be the same for inline selectors.
2585 // a subclass of AdfDhtmlSimpleFloat will override.
2586 var focusContentElement = this.GetFocusContent();
2587 var firstFocus = AdfFocusUtils.getFirstTabStop(focusContentElement);
2588 if (!(firstFocus))
2589 {
2590
2591 // fall back to the outer frame if focus can not be established
2592 // this would occur for the subclass AdfDhtmlSimpleFloat. The
2593 // "dialog" overrides the protected GetFocusContent() to look in the
2594 // center of the dialog. If the dialog content doesn't contain a
2595 // focusable element, fall back to the outer frame where something in
2596 // the header (closeIcon) or footer (button bar) will have focus elements.
2597
2598 if (rootElement != focusContentElement) {
2599 // root is not the same as GetFocusContent, look again
2600 firstFocus = AdfFocusUtils.getFirstTabStop(rootElement);
2601 }
2602
2603 if (!(firstFocus))
2604 {
2605 // if a focus stop cannot be found in the content, force focus by
2606 // setting the tabindex and then setting focus.
2607 focusContentElement.tabIndex = -1;
2608 AdfFocusUtils.focusElement(focusContentElement);
2609 }
2610 }
2611
2612 if (firstFocus)
2613 {
2614 // bug 14562816 - workaround for an issue seen in IE8 where the first focus is not
2615 // sticking for the second modal dialog.
2616 var agent = AdfAgent.AGENT;
2617 if (!AdfPage.PAGE.isScreenReaderMode() &&
2618 (AdfAgent.IE_PLATFORM != agent.getPlatform() ||
2619 (AdfAgent.IE_PLATFORM == agent.getPlatform() && agent.getVersion() > 8)))
2620 AdfFocusUtils.focusElement(firstFocus);
2621 else
2622 //bug 10251301 delay focus to allow for a heavy keydown that could be redirected
2623 //to the content of the popup versus the launcher component.
2624 AdfFocusUtils.focusElementDelayed(firstFocus, 1000);
2625 }
2626}
2627
2628/**
2629 * Returns the content dom node for the popup. This method should be overridden
2630 * by subclasses to return the inner content area versus the outer border/title
2631 * dom structure.
2632 *
2633 * @return {HTMLElement} content area of the popup
2634 */
2635AdfDhtmlPopupWindow.prototype.GetFocusContent = function()
2636{
2637 var element = this.getElement();
2638 return element;
2639}
2640
2641/**
2642 * Registers this floating element with the position manager based on the
2643 * alignment hint. Unregisters if already registered.
2644 *
2645 * @param {String} hintAlign alignment constants
2646 */
2647AdfDhtmlPopupWindow.prototype.Position = function(hintAlign)
2648{
2649 var page = AdfPage.PAGE;
2650 var positionManager = page.getPositionManager();
2651 var positionManagerIndex = this._positionManagerIndex;
2652 if (positionManagerIndex)
2653 {
2654 positionManager.removeElement(positionManagerIndex);
2655 delete this._positionManagerIndex;
2656 }
2657
2658 var ignoreShadow = !this.HasShadow();
2659 this._positionManagerIndex = positionManager.addFloatingElement(this, hintAlign, ignoreShadow);
2660}
2661
2662/**
2663 * Registers this floating element with the position manager based on a mouse
2664 * x,y position.
2665 *
2666 * @param {Object} x,y alignment location
2667 */
2668AdfDhtmlPopupWindow.prototype._positionAtMousePointer = function(pos)
2669{
2670 this._positionManagerIndex =
2671 AdfPage.PAGE.getPositionManager().addFloatingElementByPosition(this, pos);
2672}
2673
2674/**
2675 * Registers this floating element with the position manager based on screen center position.
2676 */
2677AdfDhtmlPopupWindow.prototype._positionAtScreenCenter = function()
2678{
2679 var page = AdfPage.PAGE;
2680 var positionManager = page.getPositionManager();
2681 var positionManagerIndex = this._positionManagerIndex;
2682 if (positionManagerIndex)
2683 {
2684 positionManager.removeElement(positionManagerIndex);
2685 delete this._positionManagerIndex;
2686 }
2687
2688 var ignoreShadow = !this.HasShadow();
2689 this._positionManagerIndex = positionManager.addFloatingElementByPosition(this, this.CalcAlignPosition(), ignoreShadow);
2690}
2691
2692
2693/**
2694 * Calculates the position of the dialog to center it when <b>not</b> aligned to an element.
2695 * @param {number=} leftPercentage (optional) percentage of horizontal alignment (default is .5)
2696 * @param {number=} topPercentage (optional) percentage of vertical alignment (default is .5)
2697 * @return {Object} (x, y) alignment position
2698 */
2699AdfDhtmlPopupWindow.prototype.CalcAlignPosition = function(leftPercentage, topPercentage)
2700{
2701 // if aligned by element, can not be aligned by position
2702 if (this.getAlignElement())
2703 return null;
2704
2705 if (!leftPercentage)
2706 leftPercentage = 0.5;
2707
2708 if (!topPercentage)
2709 topPercentage = 0.5;
2710
2711 var agent = AdfAgent.AGENT;
2712 var isRTL = AdfPage.PAGE.getLocaleContext().isRightToLeft();
2713
2714 var windowHeight = agent.getWindowHeight();
2715 var windowWidth = agent.getWindowWidth();
2716
2717 var docScrollTop = agent.getBrowserViewportScrollTop();
2718 var docScrollLeft = agent.getBrowserViewportScrollLeft();
2719
2720 // in FF the scrollbar height is included in the window height sometimes.
2721 // try to remove the scrollbar height from the window size
2722 if (docScrollTop > 0 && agent.getPlatform() == AdfAgent.GECKO_PLATFORM)
2723 {
2724 windowHeight = Math.min(windowHeight, agent.getDomDocument().body.clientHeight);
2725 }
2726
2727 var w = this.getWidth();
2728 var h = this.getHeight();
2729
2730 var dir = isRTL ? -1 : 1;
2731 var top = Math.max(0, Math.round((windowHeight * topPercentage) - (h / 2))) + docScrollTop;
2732 var left = Math.max(0, Math.round((windowWidth * leftPercentage) - (dir * (w / 2)))) + (dir * docScrollLeft);
2733
2734 // verify that the dialog will fit in the window with the target position; otherwise,
2735 // try to readjust with the deltas
2736 var ydelta = (windowHeight + docScrollTop) - (top + h);
2737 if (ydelta < 0)
2738 {
2739 top = Math.max(docScrollTop, top + ydelta);
2740 }
2741 var xdelta = (windowWidth + docScrollLeft) - (left + (dir * w));
2742 if (xdelta < 0)
2743 {
2744 left = Math.max(docScrollLeft, left + xdelta);
2745 }
2746
2747 var pos = {y:top, x:left};
2748
2749 return pos;
2750}
2751
2752/**
2753 * Perform a resize notification traversal when showing popup
2754 * contents so that geometry managing components are given the
2755 * opportunity to lay themselves out.
2756 *
2757 * @param {HTMLElement} target dom node
2758 */
2759AdfDhtmlPopupWindow.prototype.DoResizeNotifyDom = function(content)
2760{
2761 AdfPage.PAGE.doResizeNotifyDom(content, false);
2762}
2763
2764/**
2765 * Finds all child DOM elements that have scroll values and saves their scroll value information.
2766 *
2767 * By default, vertical scroll values are lost when DOM elements are reparented - which happens when
2768 * popups are hidden and then reshown. This method looks for child elements that have vertical
2769 * scroll values. Any scroll values found are saved so they can be restored if later the popup is
2770 * shown again.
2771 *
2772 * @param {HTMLElement} domElement the root domElement in the popup
2773 */
2774AdfDhtmlPopupWindow.prototype.SaveScrollValues = function(domElement)
2775{
2776 var childElements = domElement.getElementsByTagName("div");
2777 var childCount = childElements.length;
2778
2779 for (var i = 0; i < childCount; i++)
2780 {
2781 var currElement = childElements[i];
2782 var scrollTop = currElement.scrollTop;
2783 if (scrollTop > 0)
2784 {
2785 currElement.setAttribute(AdfDhtmlPopupWindow._SCROLL_POSITION, scrollTop);
2786 }
2787 }
2788}
2789
2790/**
2791 * Finds all child DOM elements that need their vertical scroll values restored and restores them.
2792 *
2793 * By default, vertical scroll values are lost when DOM elements are reparented - which happens when
2794 * popups are hidden and then reshown. This method looks for saved scroll values on components
2795 * (that were saved during the popup hide method, and restores any that are found.
2796 *
2797 * @param {HTMLElement} domElement the root domElement in the popup
2798 */
2799AdfDhtmlPopupWindow.prototype.RestoreScrollValues = function(domElement)
2800{
2801 var childElements = domElement.getElementsByTagName("div");
2802 var childCount = childElements.length;
2803 for (var y = 0; y < childCount; y++)
2804 {
2805 var currElement = childElements[y];
2806 var scrollPosition = currElement.getAttribute(AdfDhtmlPopupWindow._SCROLL_POSITION);
2807 if (scrollPosition && scrollPosition > 0)
2808 AdfDomUtils.setScrollTop(currElement, scrollPosition);
2809 }
2810}
2811
2812/**
2813 * Returns the clientId of the launching source if provided using
2814 * the AdfRichPopup.HINT_LAUNCH_ID popup hint. The launch source
2815 * id is passed as a popup hint by default when using showPopupBehavior.
2816 *
2817 * @return {String:null} clientId of the launching source or null if not provided
2818 */
2819AdfDhtmlPopupWindow.prototype.getLaunchSourceId = function()
2820{
2821 return this._launchSourceId;
2822}
2823
2824/**
2825 * @return {Boolean} <code>true<code> if the popup window should steal focus when
2826 * opened. The <code>AdfDhtmlPopupWindow.HINT_FOCUS</code> sets this value.
2827 */
2828AdfDhtmlPopupWindow.prototype.GetFocusOnOpen = function()
2829{
2830 return (this._focusHint ? true : false);
2831}
2832
2833/**
2834 * @param {Boolean} focusHint determines if the popup window should steal focus when
2835 * opened. The <code>AdfDhtmlPopupWindow.HINT_FOCUS</code> sets this value.
2836 */
2837AdfDhtmlPopupWindow.prototype.SetFocusOnOpen = function(focusHint)
2838{
2839 this._focusHint = focusHint;
2840}
2841
2842/**
2843 * Announces a popup status change to assistive technologies.
2844 *
2845 * @param {String} messageKey identifies the message to announce
2846 */
2847AdfDhtmlPopupWindow.prototype._announce = function(messageKey) {
2848 var page = AdfPage.PAGE;
2849 var message = page.getLookAndFeel().getTranslatedString(messageKey);
2850 page.announceToAssistiveTechnology(message);
2851}
2852
2853/**
2854 * @return {int:null} the value passed in by the <code>AdfDhtmlPopupWindow.HINT_MAX_WIDTH</code>
2855 * popup hint.
2856 */
2857AdfDhtmlPopupWindow.prototype.GetMaxWidth = function()
2858{
2859 return this._maxWidth;
2860}
2861
2862/**
2863 * Checks to see if the "ancestorNode" is a ancestor of "node"
2864 * or if they are the same. This is a popup specific version of
2865 * {@link AdfDomUtils.isAncestorOrSelf} that jumps back to the root dom
2866 * element of a open popup so that it reflects back to the origianl dom
2867 * structure before a popup is open. When the popup is open, it's content is
2868 * reparented in the document.
2869 *
2870 * @param {Node} ancestorNode some root node in the document
2871 * @param {Node} domElement target element to check if it is in the "logical" heritage of
2872 * of the ancestorNode
2873 * @return {boolean} <code>true</code> if the domElement is found within the heritage of the
2874 * ancestorNode.
2875 */
2876AdfDhtmlPopupWindow.isAncestorOrSelf = function(ancestorNode, domElement)
2877{
2878 var agent = AdfAgent.AGENT;
2879 while (domElement)
2880 {
2881 if (ancestorNode == domElement)
2882 return true;
2883
2884 if (domElement.nodeType == 1 && domElement.hasAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO))
2885 {
2886 popupId = domElement.getAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO);
2887 domElement = agent.getElementById(popupId)
2888 }
2889 else
2890 domElement = domElement.parentNode;
2891 }
2892
2893 return false;
2894}
2895
2896/**
2897 * Checks to see if the "domNode" is the root of the popupWindow.
2898 *
2899 * @param {Node} domNode target element to check if it is the root of the popupWindow
2900 * @return {boolean} <code>true</code> if the domNode is root of a popupWindow.
2901 */
2902AdfDhtmlPopupWindow.isPopupWindow = function(domNode)
2903{
2904 AdfAssert.assertDomNode(domNode);
2905
2906 if (domNode.nodeType == 1 && domNode.hasAttribute(AdfDhtmlPopupWindow.__POPUPID_EXPANDO))
2907 return true;
2908
2909 return false;
2910}
2911
2912/**
2913 * @param {String} id of the component that should establish focus when the popup is
2914 * dismissed.
2915 * @return {void}
2916 */
2917AdfDhtmlPopupWindow.prototype.setRestoreFocusId = function(id)
2918{
2919 this._restoreFocusId = id;
2920
2921 AdfLogger.LOGGER.fine("In AdfDhtmlPopupWindow#setRestoreFocusId(), _restoreFocusId set to " + this._restoreFocusId);
2922}
2923AdfAbstractFloatingElement.prototype.setPosition = function(positionTop, positionLeft)
2924{
2925 if (!isNaN(positionTop))
2926 positionTop += "px";
2927 if (!isNaN(positionLeft))
2928 positionLeft += "px";
2929 var component = AdfPage.PAGE.findComponent(this._componentId);
2930 var isFullScreen = component.getProperty(AdfDhtmlPopupHints.POPUP_FULL_SCREEN);
2931 var isFullHeightScreen = component.getProperty(AdfDhtmlPopupHints.POPUP_FULL_HEIGHT_PARTIAL_SCREEN);
2932 if(isFullScreen)
2933 {
2934 this._rootElement.style.left = "0px";
2935 if(document.body.style.position === "fixed")
2936 this._rootElement.style.top = AdfAgent.AGENT.getAttribute(document.body, AdfDhtmlPopupWindow._SCROLL_POSITION) + "px";
2937 else
2938 this._rootElement.style.top = "0px";
2939 }
2940 else if(isFullHeightScreen)
2941 {
2942 this._rootElement.style.left = positionLeft;
2943 this._rootElement.style.top = AdfAgent.AGENT.getAttribute(document.body, AdfDhtmlPopupWindow._SCROLL_POSITION) + "px";
2944 }
2945 else
2946 {
2947 this._rootElement.style.left = positionLeft;
2948 this._rootElement.style.top = positionTop;
2949 }
2950
2951 if(AdfDhtmlShadowDecorator.hasShadowDecorator(this.getShadowAnchor()))
2952 {
2953 AdfDhtmlShadowDecorator.moveShadowDecorator(this.getShadowAnchor());
2954 }
2955}
2956
2957AdfDhtmlModalityManager.prototype._createGlassPane = function()
2958{
2959 var agent = AdfAgent.AGENT;
2960 var domDocument = AdfPage.PAGE.getDomDocument();
2961 var el = domDocument.createElement("div");
2962 var style = el.style;
2963 var domWindow = agent.getDomWindow();
2964
2965 el.className = "AFModalGlassPane";
2966 style.width = agent.getWindowScrollWidth(domWindow) + "px";
2967 style.height = agent.getWindowScrollHeight(domWindow) + "px";
2968
2969 agent.disableUserSelect(el);
2970
2971 // add void handlers
2972 agent.addBubbleEventListener(el, "keydown", AdfAgent.eatEventCallback);
2973 agent.addBubbleEventListener(el, "keyup", AdfAgent.eatEventCallback);
2974 agent.addBubbleEventListener(el, "keypress", AdfAgent.eatEventCallback);
2975 agent.addBubbleEventListener(el, "mousedown", AdfAgent.eatEventCallback);
2976 agent.addBubbleEventListener(el, "mouseup", AdfAgent.eatEventCallback);
2977 agent.addBubbleEventListener(el, "mouseover", AdfAgent.eatEventCallback);
2978 agent.addBubbleEventListener(el, "mouseout", AdfAgent.eatEventCallback);
2979 agent.addBubbleEventListener(el, "click", AdfAgent.eatEventCallback);
2980 agent.addBubbleEventListener(el, "focusin", AdfAgent.eatEventCallback);
2981 agent.addBubbleEventListener(el, "focus", AdfAgent.eatEventCallback);
2982
2983 return el;
2984}
2985
2986AdfDhtmlModalityManager.prototype._handleResize = function()
2987{
2988 var agent = AdfAgent.AGENT;
2989 var domWindow = agent.getDomWindow();
2990 for (var i=0; i<this._glassPaneStack.length; i++)
2991 {
2992 var glassPane = this._glassPaneStack[i];
2993 glassPane.style.width = "100vw";
2994 glassPane.style.height = domWindow.innerHeight + agent.getAttribute(document.body, AdfDhtmlPopupWindow._SCROLL_POSITION)+ "px";
2995 }
2996}
2997var AdfDhtmlPopupHints = {
2998
2999TYPE: "type",
3000TYPE_MENU: "menu",
3001
3002/* boolean value indicating if focus should be placed in popup */
3003FOCUS: "focus",
3004
3005/* autodismissal hints */
3006AUTODISMISS: "autodismiss",
3007AUTODISMISS_MENU: "autodismissMenu",
3008SURROGATE_CLIENT_ID: "surrogateClientId",
3009
3010OPEN_TRANSITION : "openTransition",
3011CLOSE_TRANSITION: "closeTransition",
3012
3013TRANSITION_AUTO : "auto",
3014TRANSITION_VERTICAL : "vertically",
3015TRANSITION_HORIZONTAL : "horizontally",
3016
3017// POPUP_FULL_SCREEN: Indicates that the popup will stretch
3018// corner to corner, covering the entire screen space.
3019POPUP_FULL_SCREEN : "_afr_mobile_fullScreenPopup",
3020
3021// POPUP_FULL_HEIGHT_PARTIAL_SCREEN: Indicates that the popup
3022// will stretch to fill the height of the screen but may not cover the entire
3023// screen width.
3024POPUP_FULL_HEIGHT_PARTIAL_SCREEN : "_afr_mobile_fullHeightPartialScreenPopup",
3025
3026// POPUP_PARTIAL_SCREEN: Does not stretch
3027POPUP_PARTIAL_SCREEN : "_afr_mobile_partialScreenPopup"
3028
3029}
3030
3031AdfDhtmlPopupPeer.prototype.show = function(component, hints)
3032{
3033 AdfAssert.assertPrototype(component, AdfUIComponent);
3034 AdfAssert.assertObjectOrNull(hints);
3035
3036 // If popup if visible, do nothing
3037 var popupVisible = this.isVisible(component);
3038 if (popupVisible)
3039 {
3040 return;
3041 }
3042
3043 // In screen reader mode, an open menu could be currently open but not visible (out of scope),
3044 // as only the main page or a single popup/menu is displayed at a time. In this case we want to
3045 // activate the popup.
3046 var popupWindow = this.getPopupWindow(component, component.getClientId());
3047 if (popupWindow && popupWindow.hasSpecialRenderingForScreenReader())
3048 {
3049 if (popupWindow.GetFocusOnOpen && !popupWindow.GetFocusOnOpen())
3050 return;
3051
3052 // If the AdfDhtmlPopupWindow has an activate method (true when of type AdfDhtmlSimpleFloat),
3053 // activate it.
3054 if (popupWindow.activate)
3055 {
3056 popupWindow.activate();
3057 return;
3058 }
3059 }
3060
3061 var contentDelivery = component.getContentDelivery();
3062 var isLazy = (contentDelivery == AdfRichPopup.CONTENT_DELIVERY_LAZY),
3063 isLazyUncached = (contentDelivery == AdfRichPopup.CONTENT_DELIVERY_LAZY_UNCACHED);
3064
3065 var launchId = null;
3066 if (hints)
3067 launchId = hints[AdfRichPopup.HINT_LAUNCH_ID];
3068
3069 if (isLazy || isLazyUncached)
3070 {
3071 // if we have already posted the fetch event, return and wait. If the showPopupBehavior
3072 // is triggered on a chatty event, this might be called while we are waiting on content delivery
3073 var isFetching = component._isFetching;
3074 if (isFetching)
3075 {
3076 AdfLogger.LOGGER.warning("Waiting on popup content delivery: " + component.getClientId());
3077 return;
3078 }
3079
3080 if (!component._hasContent)
3081 {
3082 // cache the popup hints under the page service while waiting for
3083 // lazy content delivery. use the component's client id to create
3084 // a map safe key.
3085 var page = AdfPage.PAGE;
3086 var hintsPagePropertyKey = AdfDhtmlPopupPeer._createPagePropertyKey(component.getClientId());
3087 page.setPageProperty(hintsPagePropertyKey, hints);
3088
3089 var params;
3090
3091 if (launchId != null)
3092 {
3093 params = new Object();
3094 params.launchId = launchId;
3095 }
3096
3097 // push certian hints into component properties. we do not raise a property sync event
3098 // because we are already going to the server.
3099 this.syncPrivateProperties(component, hints, true);
3100
3101 component._isFetching = true;
3102 new AdfContentFetchEvent(component, AdfContentFetchEvent.FETCH_EVENT_TYPE, params).queue();
3103 return;
3104 }
3105 }
3106
3107 // for lazy uncached we need to reset our flag so that it can be
3108 // loaded again from server.
3109 if (isLazyUncached)
3110 {
3111 delete component._hasContent;
3112 }
3113
3114 // if fetchCanceled was called before lazy content delivery, cancel opening the popup
3115 if (component._isFetchCanceled)
3116 {
3117 delete component._isFetchCanceled;
3118
3119 // toggle off the shown state and sync with the server by forcing a proeprty sync event
3120 this._setShown(component, false);
3121 return;
3122 }
3123
3124 var openEvent = new AdfPopupOpeningEvent(component, hints);
3125 component.broadcast(openEvent);
3126 if (!openEvent.isCanceled())
3127 {
3128 // in rare cases hints may be null
3129 if (!(hints))
3130 {
3131 hints = new Object();
3132 }
3133
3134 var autoDismissalTimeout = component.getAutoDismissalTimeout();
3135
3136 if (autoDismissalTimeout && !isNaN(autoDismissalTimeout) && autoDismissalTimeout > 0)
3137 {
3138 hints[AdfDhtmlPopupWindow.HINT_AUTODISMISS_POPUP_TIMEOUT] = autoDismissalTimeout * 1000;
3139 }
3140
3141 // hint that inidcates we are restoring visible state due to dom replacement
3142 var isRestoreImmediate = hints[AdfDhtmlPopupWindow.HINT_RESTORE_IMMEDIATE] ? true : false;
3143
3144 // Sets the popupOpend event handler. The opened handler
3145 // will not be invoked until the popup becomes visible.
3146 hints[AdfDhtmlPopupWindow.HINT_OPENED_HANDLER] = this.createCallback(this.PopupOpened);
3147 hints[AdfDhtmlPopupWindow.HINT_OPENED_HANDLER_PARAM] = component;
3148
3149 // if restored, we disable animation
3150 if (hints[AdfDhtmlPopupWindow.HINT_ANIMATE] != AdfRichPopup.ANIMATE_FALSE)
3151 {
3152 hints[AdfDhtmlPopupWindow.HINT_ANIMATE] = component.getAnimate();
3153 hints[AdfDhtmlPopupHints.OPEN_TRANSITION] = AdfDhtmlPopupPeer._getPopupOpenTransition(component);
3154 hints[AdfDhtmlPopupHints.CLOSE_TRANSITION] = AdfDhtmlPopupPeer._getPopupCloseTransition(component);
3155 }
3156
3157 var isFullScreen = component.getProperty(AdfDhtmlPopupHints.POPUP_FULL_SCREEN);
3158 if(isFullScreen)
3159 {
3160 hints[AdfDhtmlPopupHints.POPUP_FULL_SCREEN] = isFullScreen;
3161 }
3162
3163 var isFullHeightPartialScreenPopup = component.getProperty(AdfDhtmlPopupHints.POPUP_FULL_HEIGHT_PARTIAL_SCREEN);
3164 if(isFullHeightPartialScreenPopup)
3165 {
3166 hints[AdfDhtmlPopupHints.POPUP_FULL_HEIGHT_PARTIAL_SCREEN] = isFullHeightPartialScreenPopup;
3167 }
3168
3169 var isPartialScreenPopup = component.getProperty(AdfDhtmlPopupHints.POPUP_PARTIAL_SCREEN);
3170 if(isPartialScreenPopup)
3171 {
3172 hints[AdfDhtmlPopupHints.POPUP_PARTIAL_SCREEN] = isPartialScreenPopup;
3173 }
3174
3175 // don't need to sync shown state unless the request was client only. If
3176 // we are restoring the visbile state or fetch content, then hints come from
3177 // the server.
3178 var isPropSynced = this._setShown(component, true, (isLazyUncached || isRestoreImmediate));
3179
3180 // sync private properties that hold hints if the popup's content was cached
3181 if (!isPropSynced && (!isLazyUncached && !isRestoreImmediate))
3182 this.syncPrivateProperties(component, hints);
3183
3184 this._showPopup(component, hints);
3185 }
3186 else
3187 {
3188 // toggle off the shown property and sync with the server
3189 this._setShown(component, false);
3190 }
3191}