Touch events on UIButton stop after delayed Animation is started - objective-c

I am creating a UIButton inside a UIView. If I apply a transition to the UIView the myButton_TouchUpInside touch event on the UIButton stops firing. Can anyone advise? (see edit)
(I am using Xamarin here)
UIView myView = new UIView()
{
BackgroundColor = UIColor.Black,
RestorationIdentifier = identifier,
UserInteractionEnabled = true,
ClipsToBounds = true
};
UIButton myButton = new UIButton()
{
BackgroundColor = UIColor.Red,
UserInteractionEnabled = true
};
myButton.TouchUpInside += myButton_TouchUpInside;
myButton.SizeToFit();
myButton.Frame = new CGRect(0, 10, myButton.Bounds.Width, myButton.Bounds.Height);
myView.AddSubview(myButton);
View.AddSubview(myView);
Click events fire at this point. If I add a transition they stop working after the transition has occurred, I presume they have been left behind in the transition:
var myNewFrame = new CGRect(0, 50, myButton.Frame.Width, myButton.Frame.Height);
UIView.Transition(myView, 0.5, UIViewAnimationOptions.CurveEaseIn, () => { myView.Frame = myNewFrame; }, null);
I have read that the Frame of the UIButton is the key here. I checked the Frame after adding it to the UIView and then again in the completed Action in the UIView.Transition (not shown in the code above) and it's size and position are exactly the same.
edit
It isn't the transition that's causing the issue, its the animation that follows (the UIView slides then after X seconds it fades out). Directly following the transition is this code:
UIView.Animate(0.25, 10, UIViewAnimationOptions.CurveEaseInOut, () => { myView.Alpha = 0; }, () => { myView.RemoveFromSuperview(); });
If I remove this, it works.

OK, rather than using the inbuilt delay property I wrapped it in an async method as so:
UIView.Transition(myView, 0.5, UIViewAnimationOptions.CurveEaseIn, () => { myView.Frame = myNewFrame; }, ()=> {FadeOut(duration)});
private async FadeOut(int duration){
await Task.Delay(duration * 1000);
UIView.Animate(0.25, 0, UIViewAnimationOptions.CurveEaseInOut, () => { myView.Alpha = 0; }, () => { myView.RemoveFromSuperview(); });
}

Related

How to work with EventListeners for draggable scrolling?

I'm trying to build a calendar in which you can scroll. I would like to achieve the scrolling also by dragging. So I use EventListeners.
mousemove continuously triggers, after the first mousedown, even if I already released the mouse. So the removeEventListeners don't really work. I don't quite understand what's wrong or how to get the interactions between all Listeners to work correctly.
Here is my CodeSandBox
mounted() {
this.initScrollCalendar()
},
methods: {
initScrollCalendar() {
const calendar = this.$refs.calendar
calendar.scrollLeft = this.position.left;
calendar.addEventListener('mousedown', (e) => this.mouseDownHandler())
},
mouseDownHandler() {
const calendar = this.$refs.calendar
calendar.addEventListener('mousemove', (e) => this.mouseMoveHandler(e) )
calendar.addEventListener('mouseup', this.mouseUpHandler());
},
mouseMoveHandler(e) {
console.log("Move")
const calendar = this.$refs.calendar
const rect = calendar.getBoundingClientRect()
const clientX = e.clientX - rect.left
const dx = clientX - this.position.x
calendar.scrollLeft = this.position.left + dx
},
mouseUpHandler() {
console.log("Up")
const calendar = this.$refs.calendar
calendar.removeEventListener('mousemove', (e) => this.mouseMoveHandler(e));
calendar.removeEventListener('mouseup', this.mouseUpHandler());
}
}
I ended up using vue-dragscroll. Works like a charm and the setup is totally simple. If needed, I can also set a starting position of my scroll container.
Don't forget overflow: auto in css
<div ref="scrollContainer" v-dragscroll>
...
</div>
// Setting starting point
const scrollContainer = this.$refs.scrollContainer
scrollContainer.scrollLeft = 500;

vue, svg onmove dragging not work correctly with a ViewBox

I try to make a rectangle draggable. When I add a ViewBox to the svg the drag position is not correct anymore, without it works perfect. I think i need a scale factor. Have someone a solution?
Here is my example
https://codesandbox.io/embed/vue-interactjs-7t0nr
My drag logic
interact(o).draggable({
onmove: event => {
//let mouse = this.$parent.createSVGPoint();
//console.log(mouse);
//mouse.x = event.dx;
//console.log(mouse.x);
//mouse.y = event.dy;
//mouse.matrixTransform(this.$parent.getScreenCTM());
let index = event.target.attributes.index.value;
this.points[index].x += event.dx;
this.points[index].y += event.dy;
}
});
Update
Found a solution with a scale factor; i have add this to my example
onmove: event => {
let index = event.target.attributes.index.value;
this.points[index].x += event.dx * this.scale;
this.points[index].y += event.dy * this.scale;
}
mounted() {
this.calculateScale();
window.addEventListener("resize", this.calculateScale);
},
beforeDestroy() {
window.removeEventListener("resize", this.calculateScale);
},
methods: {
calculateScale() {
let rootRect = this.$refs.mainSvg.getBoundingClientRect();
this.scale = this.svgWidth / rootRect.width;
console.log(this.scale);
}
}

Add a fade out with CreateJS gang

Im looking for a way to set up a fade in and fade out with CreateJS.I'm completely new on CreateJS and I wish to create a little advertise of 2 differents layouts, each one with some little layouts inside which they will appear by slide or fade in-out animation.
This is my try, I'm not sure if what I did is right but some steps work and other not. Any help is really welcome.
** Finally this is the sequence I wish to develop it in 10 seconds:
** Frame 1
-The background, product image should appear immediately on the first frame.
-Fade in the titleFrameOne.
-Then fade in the blueText.
-frame 1 should wait for two seconds.
-Fade out all content on frame one except the background.
**Frame 2
-Fade in the titleFrameOne.
-Then fade in the greyCopy.
-At the same time as the grey copy animate the stamp should animate from the top (off screen) to its final position, and bounce when it lands. I need to create an effect that makes it appear to fall from the sky and bounce a bit on the ground when it lands with its shadow ate the end.
-Fade out all content on frame 2 except the background image.
Also I was wondering if I can do this animation in CSS so if it's possible I wish to know how I reach the id's created in JS and manipulate them on my CSS style sheet.
I precise that I'm using:
PreloadJS
EaselsJS
TweenJS
Thanks everyone
HTML:
<body>
<canvas id="stage" width="300" height="250"></canvas>
</body>
JS:
// JavaScript Document
window.onload = function() {
console.log("ad");
// variables here.
//Frame 1
var background;
var products;
var titleFrameOne;
var blueText;
//Frame 2
var titleFrameTwo;
var greyCopy;
var stamp;
var shadow;
// store a reference to the canvas which we will draw on.
var stage = new createjs.Stage("stage");
// register the stage to handle mouse events.
stage.enableMouseOver(10);
// register the Ticker to listen for the tick event.
createjs.Ticker.addEventListener("tick", handleTick, false);
// redraw the canvas - like Event.ENTER_FRAME in Adobe Flash.
function handleTick(event) {
stage.update();
}
// create a preloader to load the images.
var loader = new createjs.LoadQueue(false);
// when all images are loaded call the handleAllImageLoaded function.
loader.on('complete', handleAllImagesLoaded, this);
// provide a manifest of files and ids to be loaded.
loader.loadManifest([
{ id: "background", src: "images/background.png" },
{ id: "products", src: "images/frameOne/products.png" },
{ id: "titleFrameOne", src: "images/frameOne/titleFrameOne.png" },
{ id: "blueText", src: "images/frameOne/blueText.png" },
{ id: "titleFrameTwo", src: "images/frameTwo/titleFrameTwo.png" },
{ id: "greyCopy", src: "images/frameTwo/greyCopy.png" },
{ id: "stamp", src: "images/frameTwo/stamp.png" },
{ id: "shadow", src: "images/frameTwo/shadow.png" },
]);
function handleAllImagesLoaded() {
console.log("All the images have loaded.");
drawTheBannerBackground();
drawFrameOne();
drawFrameTwo();
}
/**********Background**************/
function drawTheBannerBackground() {
console.log("Done - background draw & animation.");
// provide the loader result for the item with id == 'background'
// as a bitmap which will be stored in our background variable.
background = new createjs.Bitmap(loader.getResult("background"));
// set the background bitmap alpha to zero.
background.alpha = 0;
// add background to the display list.
stage.addChild(background);
// animate the background bitmap alpha value to 1 over the duration of 0 milliseconds.
createjs.Tween.get(background).to({ alpha: 1 }, 0);
// after the background is drawn on the canvas draw and animate the content for frame 1.
}
/*****************************Frame 1*****************************/
function drawFrameOne() {
products = new createjs.Bitmap(loader.getResult("products"));
titleFrameOne = new createjs.Bitmap(loader.getResult("titleFrameOne"));
blueText = new createjs.Bitmap(loader.getResult("blueText"));
products.alpha = 0;
titleFrameOne.alpha = 0;
blueText.alpha = 0;
stage.addChild(products);
stage.addChild(titleFrameOne);
stage.addChild(blueText);
createjs.Tween.get(products).to({ alpha: 1 }, 0);
createjs.Tween.get(titleFrameOne).to({ alpha: 1 }, 1000);
createjs.Tween.get(blueText).to({ alpha: 1 }, 2000);
console.log("Done - products draw & animation.");
console.log("Done - titleFrameOne draw & animation.");
console.log("Done - blueText draw & animation.");
setTimeout(drawFrameTwo, 2000);
}
/*****************************Frame 2*****************************/
function drawFrameTwo() {
titleFrameTwo = new createjs.Bitmap(loader.getResult("titleFrameTwo"));
greyCopy = new createjs.Bitmap(loader.getResult("greyCopy"));
stamp = new createjs.Bitmap(loader.getResult("stamp"));
shadow = new createjs.Bitmap(loader.getResult("shadow"));
tit`enter code here`leFrameTwo.alpha = 0;
greyCopy.alpha = 0;
stamp.alpha = 0;
shadow.alpha = 0;
stage.addChild(titleFrameTwo);
stage.addChild(greyCopy);
stage.addChild(stamp);
stage.addChild(shadow);
createjs.Tween.get(titleFrameTwo).to({ alpha: 1 }, 1000);
createjs.Tween.get(greyCopy).to({ alpha: 1 }, 2000);
createjs.Tween.get(stamp).to({ alpha: 1 }, 3000);
createjs.Tween.get(shadow).to({ alpha: 1 }, 4000);
console.log("Done - titleFrameTwo draw & animation.");
console.log("Done - greyCopy draw & animation.");
console.log("Done - stamp draw & animation.");
console.log("Done - shadow draw & animation.");
}
};
Instead of using setTimeout using callback of tweenjs.
In handleAllImagesLoaded you should not call both drawFrameOne and drawFrameTwo(); it should be callback drawFrameOne
createjs.Tween.get(blueText).to({ alpha: 1 }, 2000).call(drawFrameTwo);
Please refer the document for the more info
http://www.createjs.com/docs/tweenjs/modules/TweenJS.html

Custom transition iOS 7

I have been struggling writing a custom transition to present a controller. What I would like to do is to have a side menu (right side), and when user makes a swipe gesture present this controller.
I already wrote a custom transitioning delegate which is presenting the controller, but I would like to dismiss it using the same kind of animation. I have tried and tried, but the controller dismisses with no animation at all, it just disappears.
This is what I have so far, I'm using xamarin IOS:
var container = transitionContext.ContainerView;
var fromViewController = transitionContext.GetViewControllerForKey (UITransitionContext.FromViewControllerKey);
var toViewController = transitionContext.GetViewControllerForKey (UITransitionContext.ToViewControllerKey);
var endingFrame = new RectangleF (66, container.Frame.Y, container.Frame.Width, container.Frame.Height);
var startFrame = new RectangleF (UIScreen.MainScreen.Bounds.Width, 0, 0, container.Frame.Height);
if (Presenting) {
container.AddSubview (fromViewController.View);
container.AddSubview (toViewController.View);
toViewController.View.Frame = startFrame;
UIView.Animate (TransitionDuration (transitionContext), () => {
toViewController.View.Frame = endingFrame;
}, () => {
transitionContext.CompleteTransition (true);
});
} else {
container.AddSubview (fromViewController.View);
container.AddSubview (toViewController.View);
UIView.Animate (TransitionDuration (transitionContext), () => {
fromViewController.View.Frame = startFrame;
}, () => {
transitionContext.CompleteTransition (true);
});
}
I think the problem is with the frames, I don't know if I'm setting them correctly.
please help!!

dojo non-modal dialog

Is there a way to create a non-modal dialog window using dojo? jQuery UI supports both modal and non-modal dialog boxes. I am trying to convert a SilverLight application to HTML/javascript and finding it difficult to create non-modal windows using dojo.
You can set the display of the underlay to 'none', and you will have a non-modal Dialog. To do that, set the class of the Dialog to 'nonModal' (that's just a convention I'm creating right now), and in the CSS for the page, have an entry for .nonModal_underlay.
require(['dijit/form/Button','dijit/Dialog'],
function (Button, Dialog) {
var d = new Dialog({
'title':'I am nonmodal',
'class':'nonModal'
});
});
.nonModal_underlay {
display:none;
}
you might try dojox.layout.FloatingPane
Hi Just add this in your css
.dijitDialogUnderlayWrapper{
display:none !important
}
For people that need truly modeless Dialog, Roy J provides only partial solution as the focus still is held within the Dialog. To fix this, you can copy the dijit/Dialog.js and its dijit/templates/Dialog.html to your own folder structure and rename them to ModelessDialog. Then remove the focus handler, the key handler and the underlay. Here is the full result:
define([
"require",
"dojo/_base/array", // array.forEach array.indexOf array.map
"dojo/aspect",
"dojo/_base/declare", // declare
"dojo/Deferred", // Deferred
"dojo/dom", // dom.isDescendant
"dojo/dom-class", // domClass.add domClass.contains
"dojo/dom-geometry", // domGeometry.position
"dojo/dom-style", // domStyle.set
"dojo/_base/fx", // fx.fadeIn fx.fadeOut
"dojo/i18n", // i18n.getLocalization
"dojo/keys",
"dojo/_base/lang", // lang.mixin lang.hitch
"dojo/on",
"dojo/ready",
"dojo/sniff", // has("ie") has("opera") has("dijit-legacy-requires")
"dojo/window", // winUtils.getBox, winUtils.get
"dojo/dnd/Moveable", // Moveable
"dojo/dnd/TimedMoveable", // TimedMoveable
"dijit/focus",
"dijit/_base/manager", // manager.defaultDuration
"dijit/_Widget",
"dijit/_TemplatedMixin",
"dijit/_CssStateMixin",
"dijit/form/_FormMixin",
"dijit/_DialogMixin",
"dijit/layout/ContentPane",
"dijit/layout/utils",
"dojo/text!./templates/ModelessDialog.html",
"dijit/a11yclick", // template uses ondijitclick
"dojo/i18n!dijit/nls/common"
], function(require, array, aspect, declare, Deferred,
dom, domClass, domGeometry, domStyle, fx, i18n, keys, lang, on, ready, has, winUtils,
Moveable, TimedMoveable, focus, manager, _Widget, _TemplatedMixin, _CssStateMixin, _FormMixin, _DialogMixin,
ContentPane, utils, template){
// module:
// company/common/ModelessDialog
var resolvedDeferred = new Deferred(), _DialogBase, ds = null, DialogLevelManager = null, ModelessDialog,
_currentDialog = null;
resolvedDeferred.resolve(true);
_DialogBase = declare("dijit._DialogBase" + (has("dojo-bidi") ? "_NoBidi" : ""),
[_TemplatedMixin, _FormMixin, _DialogMixin, _CssStateMixin], {
templateString: template,
baseClass: "dijitDialog",
cssStateNodes: {
closeButtonNode: "dijitDialogCloseIcon"
},
// Map widget attributes to DOMNode attributes.
_setTitleAttr: { node: "titleNode", type: "innerHTML" },
// open: [readonly] Boolean
// True if ModelessDialog is currently displayed on screen.
open: false,
// duration: Integer
// The time in milliseconds it takes the dialog to fade in and out
duration: manager.defaultDuration,
// refocus: Boolean
// A Toggle to modify the default focus behavior of a ModelessDialog, which
// is to re-focus the element which had focus before being opened.
// False will disable refocusing. Default: true
refocus: true,
// autofocus: Boolean
// A Toggle to modify the default focus behavior of a ModelessDialog, which
// is to focus on the first dialog element after opening the dialog.
// False will disable autofocusing. Default: true
autofocus: true,
// _firstFocusItem: [private readonly] DomNode
// The pointer to the first focusable node in the dialog.
// Set by `dijit/_DialogMixin._getFocusItems()`.
_firstFocusItem: null,
// _lastFocusItem: [private readonly] DomNode
// The pointer to which node has focus prior to our dialog.
// Set by `dijit/_DialogMixin._getFocusItems()`.
_lastFocusItem: null,
// draggable: Boolean
// Toggles the movable aspect of the ModelessDialog. If true, ModelessDialog
// can be dragged by it's title. If false it will remain centered
// in the viewport.
draggable: true,
_setDraggableAttr: function(/*Boolean*/ val){
// Avoid _WidgetBase behavior of copying draggable attribute to this.domNode,
// as that prevents text select on modern browsers (#14452)
this._set("draggable", val);
},
// maxRatio: Number
// Maximum size to allow the dialog to expand to, relative to viewport size
maxRatio: 0.8,
// closable: Boolean
// ModelessDialog show [x] icon to close itself, and ESC key will close the dialog.
closable: true,
_setClosableAttr: function(val){
this.closeButtonNode.style.display = val ? "" : "none";
this._set("closable", val);
},
postMixInProperties: function(){
var _nlsResources = i18n.getLocalization("dijit", "common");
lang.mixin(this, _nlsResources);
this.inherited(arguments);
},
postCreate: function(){
domStyle.set(this.domNode, {
display: "none",
position: "absolute"
});
this.ownerDocumentBody.appendChild(this.domNode);
this.inherited(arguments);
aspect.after(this, "onExecute", lang.hitch(this, "hide"), true);
aspect.after(this, "onCancel", lang.hitch(this, "hide"), true);
this._modalconnects = [];
},
onLoad: function(){
// summary:
// Called when data has been loaded from an href.
// Unlike most other callbacks, this function can be connected to (via `dojo.connect`)
// but should *not* be overridden.
// tags:
// callback
// when href is specified we need to reposition the dialog after the data is loaded
// and find the focusable elements
this.resize();
this._position();
if(this.autofocus && DialogLevelManager.isTop(this)){
this._getFocusItems();
focus.focus(this._firstFocusItem);
}
this.inherited(arguments);
},
focus: function(){
this._getFocusItems();
focus.focus(this._firstFocusItem);
},
_endDrag: function(){
// summary:
// Called after dragging the ModelessDialog. Saves the position of the dialog in the viewport,
// and also adjust position to be fully within the viewport, so user doesn't lose access to handle
var nodePosition = domGeometry.position(this.domNode),
viewport = winUtils.getBox(this.ownerDocument);
nodePosition.y = Math.min(Math.max(nodePosition.y, 0), (viewport.h - nodePosition.h));
nodePosition.x = Math.min(Math.max(nodePosition.x, 0), (viewport.w - nodePosition.w));
this._relativePosition = nodePosition;
this._position();
},
_setup: function(){
// summary:
// Stuff we need to do before showing the ModelessDialog for the first
// time (but we defer it until right beforehand, for
// performance reasons).
// tags:
// private
var node = this.domNode;
if(this.titleBar && this.draggable){
// prevent overload, see #5285
if(has("ie") == 6) {
this._moveable = new TimedMoveable(node, { handle: this.titleBar });
} else {
this._moveable = new Moveable(node, { handle: this.titleBar });
}
aspect.after(this._moveable, "onMoveStop", lang.hitch(this, "_endDrag"), true);
}else{
domClass.add(node, "dijitDialogFixed");
}
},
_size: function(){
// TODO: remove for 2.0
this.resize();
},
_position: function(){
// summary:
// Position the dialog in the viewport. If no relative offset
// in the viewport has been determined (by dragging, for instance),
// center the dialog. Otherwise, use the ModelessDialog's stored relative offset,
// adjusted by the viewport's scroll.
if(!domClass.contains(this.ownerDocumentBody, "dojoMove")){ // don't do anything if called during auto-scroll
var node = this.domNode,
viewport = winUtils.getBox(this.ownerDocument),
p = this._relativePosition,
bb = p ? null : domGeometry.position(node),
l = Math.floor(viewport.l + (p ? p.x : (viewport.w - bb.w) / 2)),
t = Math.floor(viewport.t + (p ? p.y : (viewport.h - bb.h) / 2))
;
domStyle.set(node, {
left: l + "px",
top: t + "px"
});
}
},
show: function(){
// summary:
// Display the dialog
// returns: dojo/promise/Promise
// Promise object that resolves when the display animation is complete
if(this.open){
return resolvedDeferred.promise;
}
if(_currentDialog && _currentDialog != this) {
_currentDialog.destroy();
}
_currentDialog = this;
if(!this._started){
this.startup();
}
// first time we show the dialog, there's some initialization stuff to do
if(!this._alreadyInitialized){
this._setup();
this._alreadyInitialized = true;
}
if(this._fadeOutDeferred){
// There's a hide() operation in progress, so cancel it, but still call DialogLevelManager.hide()
// as though the hide() completed, in preparation for the DialogLevelManager.show() call below.
this._fadeOutDeferred.cancel();
DialogLevelManager.hide(this);
}
// Recenter ModelessDialog if user scrolls browser. Connecting to document doesn't work on IE, need to use window.
// Be sure that event object doesn't get passed to resize() method, because it's expecting an optional
// {w: ..., h:...} arg.
var win = winUtils.get(this.ownerDocument),
// fade-in Animation object, setup below
fadeIn = null, promise;
this._modalconnects.push(on(win, "scroll", lang.hitch(this, "resize", null)));
//this._modalconnects.push(on(this.domNode, "keydown", lang.hitch(this, "_onKey")));
domStyle.set(this.domNode, {
opacity: 0,
display: ""
});
this._set("open", true);
this._onShow(); // lazy load trigger
this.resize();
this._position();
this._fadeInDeferred = new Deferred(lang.hitch(this, function(){
fadeIn.stop();
delete this._fadeInDeferred;
}));
// If delay is 0, code below will delete this._fadeInDeferred instantly, so grab promise while we can.
promise = this._fadeInDeferred.promise;
fadeIn = fx.fadeIn({
node: this.domNode,
duration: this.duration,
beforeBegin: lang.hitch(this, function(){
DialogLevelManager.show(this/*, this.underlayAttrs*/);
}),
onEnd: lang.hitch(this, function(){
if(this.autofocus && DialogLevelManager.isTop(this)){
// find focusable items each time dialog is shown since if dialog contains a widget the
// first focusable items can change
this._getFocusItems();
focus.focus(this._firstFocusItem);
}
this._fadeInDeferred.resolve(true);
delete this._fadeInDeferred;
})
}).play();
return promise;
},
hide: function(){
// summary:
// Hide the dialog
// returns: dojo/promise/Promise
// Promise object that resolves when the display animation is complete
// If we haven't been initialized yet then we aren't showing and we can just return.
// Likewise if we are already hidden, or are currently fading out.
_currentDialog = null;
if(!this._alreadyInitialized || !this.open){
return resolvedDeferred.promise;
}
if(this._fadeInDeferred){
this._fadeInDeferred.cancel();
}
// fade-in Animation object, setup below
var fadeOut = null, promise, h = null;
this._fadeOutDeferred = new Deferred(lang.hitch(this, function(){
fadeOut.stop();
delete this._fadeOutDeferred;
}));
// fire onHide when the promise resolves.
this._fadeOutDeferred.then(lang.hitch(this, 'onHide'));
// If delay is 0, code below will delete this._fadeOutDeferred instantly, so grab promise while we can.
promise = this._fadeOutDeferred.promise;
fadeOut = fx.fadeOut({
node: this.domNode,
duration: this.duration,
onEnd: lang.hitch(this, function(){
this.domNode.style.display = "none";
DialogLevelManager.hide(this);
this._fadeOutDeferred.resolve(true);
delete this._fadeOutDeferred;
})
}).play();
if(this._scrollConnected){
this._scrollConnected = false;
}
while(h = this._modalconnects.pop()){
h.remove();
}
if(this._relativePosition){
delete this._relativePosition;
}
this._set("open", false);
return promise;
},
resize: function(dim){
// summary:
// Called with no argument when viewport scrolled or viewport size changed. Adjusts ModelessDialog as
// necessary to keep it visible.
//
// Can also be called with an argument (by dojox/layout/ResizeHandle etc.) to explicitly set the
// size of the dialog.
// dim: Object?
// Optional dimension object like {w: 200, h: 300}
if(this.domNode.style.display != "none"){
this._checkIfSingleChild();
if(!dim){
if(this._shrunk){
// If we earlier shrunk the dialog to fit in the viewport, reset it to its natural size
if(this._singleChild){
if(typeof this._singleChildOriginalStyle != "undefined"){
this._singleChild.domNode.style.cssText = this._singleChildOriginalStyle;
delete this._singleChildOriginalStyle;
}
}
array.forEach([this.domNode, this.containerNode, this.titleBar], function(node){
domStyle.set(node, {
position: "static",
width: "auto",
height: "auto"
});
});
this.domNode.style.position = "absolute";
}
// If necessary, shrink ModelessDialog to fit in viewport and have some space around it
// to indicate that it's a popup. This will also compensate for possible scrollbars on viewport.
var viewport = winUtils.getBox(this.ownerDocument), bb, contentDim, centerSize, cb;
viewport.w *= this.maxRatio;
viewport.h *= this.maxRatio;
bb = domGeometry.position(this.domNode);
if(bb.w >= viewport.w || bb.h >= viewport.h){
dim = {
w: Math.min(bb.w, viewport.w),
h: Math.min(bb.h, viewport.h)
};
this._shrunk = true;
}else{
this._shrunk = false;
}
}
// Code to run if user has requested an explicit size, or the shrinking code above set an implicit size
if(dim){
// Set this.domNode to specified size
domGeometry.setMarginBox(this.domNode, dim);
// And then size this.containerNode
contentDim = utils.marginBox2contentBox(this.domNode, dim);
centerSize = {domNode: this.containerNode, region: "center"};
utils.layoutChildren(this.domNode, contentDim,
[ {domNode: this.titleBar, region: "top"}, centerSize ]);
// And then if this.containerNode has a single layout widget child, size it too.
// Otherwise, make this.containerNode show a scrollbar if it's overflowing.
if(this._singleChild){
cb = utils.marginBox2contentBox(this.containerNode, centerSize);
// note: if containerNode has padding singleChildSize will have l and t set,
// but don't pass them to resize() or it will doubly-offset the child
this._singleChild.resize({w: cb.w, h: cb.h});
// TODO: save original size for restoring it on another show()?
}else{
this.containerNode.style.overflow = "auto";
this._layoutChildren(); // send resize() event to all child widgets
}
}else{
this._layoutChildren(); // send resize() event to all child widgets
}
if(!has("touch") && !dim){
// If the user has scrolled the viewport then reposition the ModelessDialog. But don't do it for touch
// devices, because it will counteract when a keyboard pops up and then the browser auto-scrolls
// the focused node into view.
this._position();
}
}
},
_layoutChildren: function(){
// Override _ContentPaneResizeMixin._layoutChildren because even when there's just a single layout child
// widget, sometimes we don't want to size it explicitly (i.e. to pass a dim argument to resize())
array.forEach(this.getChildren(), function(widget){
if(widget.resize){
widget.resize();
}
});
},
destroy: function(){
if(this._fadeInDeferred){
this._fadeInDeferred.cancel();
}
if(this._fadeOutDeferred){
this._fadeOutDeferred.cancel();
}
if(this._moveable){
this._moveable.destroy();
}
var h = null;
while(h = this._modalconnects.pop()){
h.remove();
}
DialogLevelManager.hide(this);
_currentDialog = null;
this.inherited(arguments);
}
});
if(has("dojo-bidi")){
_DialogBase = declare("dijit._DialogBase", _DialogBase, {
_setTitleAttr: function(/*String*/ title){
this._set("title", title);
this.titleNode.innerHTML = title;
this.applyTextDir(this.titleNode);
},
_setTextDirAttr: function(textDir){
if(this._created && this.textDir != textDir){
this._set("textDir", textDir);
this.set("title", this.title);
}
}
});
}
ModelessDialog = declare("beacons.common.ModelessDialog", [ContentPane, _DialogBase], {
// summary:
// A modal dialog Widget.
// description:
// Pops up a modeless dialog window. ModelessDialog is extended from
// ContentPane so it supports all the same parameters (href, etc.).
// example:
// | <div data-dojo-type="beacons/common/ModelessDialog" data-dojo-props="href: 'test.html'"></div>
// example:
// | var foo = new ModelessDialog({ title: "test dialog", content: "test content" });
// | foo.placeAt(win.body());
// | foo.startup();
});
ModelessDialog._DialogBase = _DialogBase; // for monkey patching and dojox/widget/DialogSimple
DialogLevelManager = ModelessDialog._DialogLevelManager = {
// summary:
// Controls the various active "levels" on the page, starting with the
// stuff initially visible on the page (at z-index 0), and then having an entry for
// each ModelessDialog shown.
_beginZIndex: 750,
show: function(/*dijit/_WidgetBase*/ dialog/*, / *Object* / underlayAttrs*/){
// summary:
// Call right before fade-in animation for new dialog.
// Saves current focus, displays/adjusts underlay for new dialog,
// and sets the z-index of the dialog itself.
//
// New dialog will be displayed on top of all currently displayed dialogs.
//
// Caller is responsible for setting focus in new dialog after the fade-in
// animation completes.
// Save current focus
ds[ds.length - 1].focus = focus.curNode;
// Set z-index a bit above previous dialog
var zIndex = ds[ds.length - 1].dialog ? ds[ds.length - 1].zIndex + 2 : ModelessDialog._DialogLevelManager._beginZIndex;
domStyle.set(dialog.domNode, 'zIndex', zIndex);
ds.push({dialog: dialog, /*underlayAttrs: underlayAttrs, */zIndex: zIndex});
},
hide: function(/*dijit/_WidgetBase*/ dialog){
// summary:
// Called when the specified dialog is hidden/destroyed, after the fade-out
// animation ends, in order to reset page focus, fix the underlay, etc.
// If the specified dialog isn't open then does nothing.
//
// Caller is responsible for either setting display:none on the dialog domNode,
// or calling dijit/popup.hide(), or removing it from the page DOM.
var pd, focus, idx;
if(ds[ds.length - 1].dialog == dialog){
// Removing the top (or only) dialog in the stack, return focus
// to previous dialog
ds.pop();
pd = ds[ds.length - 1]; // the new active dialog (or the base page itself)
// Adjust focus.
// TODO: regardless of setting of dialog.refocus, if the exeucte() method set focus somewhere,
// don't shift focus back to button. Note that execute() runs at the start of the fade-out but
// this code runs later, at the end of the fade-out. Menu has code like this.
if(dialog.refocus){
// If we are returning control to a previous dialog but for some reason
// that dialog didn't have a focused field, set focus to first focusable item.
// This situation could happen if two dialogs appeared at nearly the same time,
// since a dialog doesn't set it's focus until the fade-in is finished.
focus = pd.focus;
if(pd.dialog && (!focus || !dom.isDescendant(focus, pd.dialog.domNode))){
pd.dialog._getFocusItems();
focus = pd.dialog._firstFocusItem;
}
if(focus){
// Refocus the button that spawned the ModelessDialog. This will fail in corner cases including
// page unload on IE, because the dijit/form/Button that launched the ModelessDialog may get destroyed
// before this code runs. (#15058)
try{
focus.focus();
}catch(e){
;
}
}
}
}else{
// Removing a dialog out of order (#9944, #10705).
// Don't need to mess with underlay or z-index or anything.
idx = array.indexOf(array.map(ds, function(elem){
return elem.dialog;
}), dialog);
if(idx != -1){
ds.splice(idx, 1);
}
}
},
isTop: function(/*dijit/_WidgetBase*/ dialog){
// summary:
// Returns true if specified ModelessDialog is the top in the task
return ds[ds.length - 1].dialog == dialog;
}
};
// Stack representing the various active "levels" on the page, starting with the
// stuff initially visible on the page (at z-index 0), and then having an entry for
// each ModelessDialog shown.
// Each element in stack has form {
// dialog: dialogWidget,
// focus: returnFromGetFocus(),
// underlayAttrs: attributes to set on underlay (when this widget is active)
// }
ds = ModelessDialog._dialogStack = [
{dialog: null, focus: null/*, underlayAttrs: null*/} // entry for stuff at z-index: 0
];
// Back compat w/1.6, remove for 2.0
if(has("dijit-legacy-requires")){
ready(0, function(){
var requires = ["dijit/TooltipDialog"];
require(requires); // use indirection so modules not rolled into a build
});
}
ModelessDialog.closeCurrent = function() {
if(_currentDialog) {
_currentDialog.destroy();
}
};
return ModelessDialog;
});