Method from other route affects current route - vue.js

I have to 2 router view - Home.vue and List.vue. Home is the index and list is the other page.
From home I navigate to list page, then I have a method that displays 10 items.
scrolled() {
var self = this
var pageHeight = document.documentElement.offsetHeight,
windowHeight = window.innerHeight,
scrollPosition =
window.scrollY
|| window.pageYOffset
|| document.body.scrollTop + (document
.documentElement && document.documentElement.scrollTop || 0);
if (pageHeight <= windowHeight + scrollPosition) {
// code to display data
self.currentPage = self.currentPage + 1
self.getGameHistory(self.currentPage)
}
}
If scrolled to the bottom it will display 10 new items. Going back to home page the method is still working upon scrolling. I don't why it happens.
Is there a way to disable that method upon changing to other route?

Assuming, you are using scrolled event listener on window object using your mounted() lifecycle method, you must de-register the global event listener on window object:
const opts = {
mounted() {
window.addEventListener('scroll', this.scrolled);
},
beforeDestroy() {
// UN-REGISTER THE GLOBAL HANDLER BEFORE COMPONENT IS DESTROYED
window.removeEventListener('scroll', this.scrolled);
},
method: {
scrolled() {
/* Your Logic */
}
}
};

Related

How to preview image in element ui?

I am using element ui el-image. And I want to preview my image when clicked with (:preview-src-list). But When I click first time it doesnt preview anything. just add's my downloaded image. So I need to click 2 times. But I want to click 1 time.
Here is my template code:
<el-image :src="src"
:preview-src-list="srcList"
#click="imgClick"></el-image>
ts code:
src = null;
srcList = [];
product = 'shoe1';
imgClick() {
prevImg(product).then(resp => {
const url = window.URL.createObjectURL(new Blob([resp.data]));
this.srclist = [url];
});
}
#Watch("product")
changed(value) {
getProductImage(value).then(resp => {
const url = window.URL.createObjectURL(new Blob([resp.data]));
this.src = url;
}).catc(e => {
alert(e);
});
}
mounted() {
this.changed(product);
}
I think these things happen because when you click on that image it will trigger clickHandler:
...
clickHandler() {
// don't show viewer when preview is false
if (!this.preview) {
return;
}
...
}
...
From source
And the preview is the computed property:
...
preview() {
const { previewSrcList } = this;
return Array.isArray(previewSrcList) && previewSrcList.length > 0;
}
...
From source
So nothing happened in the first click but after that you set preview-src-list and click it again then it works.
If you code is synchronous you can use event like mousedown which will trigger before click event.
<el-image
:src="url"
:preview-src-list="srcList"
#mousedown="loadImages">
</el-image>
Example
But if you code is asynchronous you can use refs and call clickHandler after that.
...
// fetch something
this.$nextTick(() => {
this.$refs.elImage.clickHandler()
})
...
Example

Why won't my MithrilJS UI render unless I call redraw after a programmatic redirect?

Here is a snippet of view code. Why won't it work without the m.redraw()? If I don't call that, the route changes and the login controller loads, but nothing is rendered into the DOM.
home.view = function(ctrl) {
console.log('in home view');
if (!mo_portal.logged_in) {
console.log('redirecting to login');
m.route("/login");
m.redraw();
return;
}
return m("div","HOME");
}
Changing route will always trigger a redraw. If you're not seeing the login page view without manually calling m.redraw it's probably down to bugs in the login controller or view that happen during the route change redraw - bugs whose failure conditions are reset when you call m.redraw again.
Here's an extension of your code with a login view and controller. mo_portal.logged_in is set to true or false depending on whether the user is one in the usersList or not, so we can test success and failure.
I took out the m.redraw (I also put the redirect logic in the home controller) and everything works fine.
var usersList = [
'john',
'alexia'
];
var mo_portal = {
username : '',
logged_in: false
};
var login = {};
login.controller = function(){
this.username = function( input ){
if( arguments.length ){
mo_portal.username = input;
mo_portal.logged_in = !!~usersList.indexOf( input );
}
return mo_portal.username;
};
};
login.view = function(ctrl){
console.log('in login view');
return [
m( 'input', { oninput : m.withAttr( 'value', ctrl.username ), value : ctrl.username() } ),
m( 'a[href=/home]', { config : m.route }, 'Login' )
];
};
var home = {};
home.controller = function(){
if (!mo_portal.logged_in) {
console.log('redirecting to login');
m.route("/login");
}
};
home.view = function(ctrl) {
console.log('in home view');
return m("div","HOME");
};
m.route( document.body, '/login', {
'/login' : login,
'/home' : home
} );
<script src="https://rawgit.com/lhorie/mithril.js/next/mithril.js"></script>
I think that's not how mithril is going to be used. Mithril does not expect a view update (aka redraw) during ongoing view construction.
I suppose you should do the route-change in the related controller.
Keep in mind, that a view is rendered evertime the page changes somehow. You probably don't want to check the login state evert time.

Dojo ListItem with Child Inputs

I have a dojo list item that is clickable.. But at the same time we like to put input elements inside the list item. The problem is that if you click on the child element(example checkbox) the listitem onclick intercepts the call first(which seems opposite of the html bubble up format). So we cannot call stoppropagation on the child element to stop the listitem from changing the page.
In the example below you will see the listitem alert come up before the checkbox alert..
How do you handle having input elements in a listitem without triggering the listitem..
fiddle::http://jsfiddle.net/theinnkeeper/HFA36/1/
ex.
var list1 = registry.byId("myList");
var item = new ListItem ({
label: "A \"programmatic\" ListItem",
moveTo: "#",
noArrow:true,
onClick : function() {
alert("listItem clicked !" + event.target.type);
}
});
list1.addChild(item);
var check = new cb({onClick:function(){alert("checkbox clicked");event.stopPropagation();}});
check.placeAt(item.containerNode.firstChild);
check.startup();
I had a similar problem a while back and noticed that the dojox/mobile/ListItem is not really great when adding extra event handlers to it (checkboxes, touch gestures, ...), so to solve that I usually extend dojox/mobile/ListItem and fix the events by myself.
For example:
var CheckedListItem = declare("dojox/mobile/CheckedListItem", [ ListItem ], {
_initializeCheckbox: function() {
this.checkbox = new CheckBox({
});
domConstruct.place(this.checkbox.domNode, this.containerNode.firstChild, "last");
this.checkbox.startup();
this.checkbox.onClick = this.onCheckboxClick;
},
onCheckboxClick: function() { },
_setOnCheckboxClickAttr: function(handler) {
this.onCheckboxClick = handler;
if (this.checkbox !== null && this.checkbox !== undefined) {
this.checkbox.onClick = handler;
}
},
_onClick: function(e) {
if (e.target !== this.checkbox.domNode) {
this.inherited(arguments);
}
},
postCreate: function() {
this.inherited(arguments);
this._initializeCheckbox();
}
});
Due to overriding _onClick() and adding additional checks I managed to get the intended behavior.
A full example can be found here: http://jsfiddle.net/LQ6Mb/

Transition with keepScrollPosition and navigateBack

We are using Durandal for our SPA application and came to a, in my opinion, common use case. We have two pages: one page is a list of entities (with filters, sorting, virtual scroll) and another is detail preview of an entity. So, user is on list page and set a filter and a list of results comes out. After scrolling a little bit down user notice an entity which he/she would like to see details for. So clicking on a proper link user is navigated to details preview page.
After "work finished" on preview page user click back button (in app itself or browser) and he/she is back on the list page. However, default 'entrance' transition scroll the page to the top and not to the position on list where user pressed preview. So in order to 'read' list further user have to scroll down where he/she was before pressing preview.
So I started to create new transition which will for certain pages (like list-search pages) keep the scroll position and for other pages (like preview or edit pages) scroll to top on transition complete. And this was easy to do however, I was surprised when I noticed that there are strange behavior on preview pages when I hit navigateBack 'button'. My already long story short, after investigation I found out that windows.history.back is completing earlier then the transition is made and this cause that preview pages are scrolled automatically down to position of previous (list) page when back button is hit. This scrolling have a very unpleasant effect on UI not mentioning that it is 'total catastrophe' for my transition.
Any idea or suggestion what could I do in this case?
Here is the code of transition. It is just a working copy not finished yet as far as I have this problem.
define(['../system'], function (system) {
var fadeOutDuration = 100;
var scrollPositions = new Array();
var getScrollObjectFor = function (node) {
var elemObjs = scrollPositions.filter(function (ele) {
return ele.element === node;
});
if (elemObjs.length > 0)
return elemObjs[0];
else
return null;
};
var addScrollPositionFor = function (node) {
var elemObj = getScrollObjectFor(node);
if (elemObj) {
elemObj.scrollPosition = $(document).scrollTop();
}
else {
scrollPositions.push({element: node, scrollPosition: $(document).scrollTop()});
}
};
var scrollTransition = function (parent, newChild, settings) {
return system.defer(function (dfd) {
function endTransition() {
dfd.resolve();
}
function scrollIfNeeded() {
var elemObj = getScrollObjectFor(newChild);
if (elemObj)
{
$(document).scrollTop(elemObj.scrollPosition);
}
else {
$(document).scrollTop(0);
}
}
if (!newChild) {
if (settings.activeView) {
addScrollPositionFor(settings.activeView);
$(settings.activeView).fadeOut(fadeOutDuration, function () {
if (!settings.cacheViews) {
ko.virtualElements.emptyNode(parent);
}
endTransition();
});
} else {
if (!settings.cacheViews) {
ko.virtualElements.emptyNode(parent);
}
endTransition();
}
} else {
var $previousView = $(settings.activeView);
var duration = settings.duration || 500;
var fadeOnly = !!settings.fadeOnly;
function startTransition() {
if (settings.cacheViews) {
if (settings.composingNewView) {
ko.virtualElements.prepend(parent, newChild);
}
} else {
ko.virtualElements.emptyNode(parent);
ko.virtualElements.prepend(parent, newChild);
}
var startValues = {
marginLeft: fadeOnly ? '0' : '20px',
marginRight: fadeOnly ? '0' : '-20px',
opacity: 0,
display: 'block'
};
var endValues = {
marginRight: 0,
marginLeft: 0,
opacity: 1
};
$(newChild).css(startValues);
var animateOptions = {
duration: duration,
easing : 'swing',
complete: endTransition,
done: scrollIfNeeded
};
$(newChild).animate(endValues, animateOptions);
}
if ($previousView.length) {
addScrollPositionFor(settings.activeView);
$previousView.fadeOut(fadeOutDuration, startTransition);
} else {
startTransition();
}
}
}).promise();
};
return scrollTransition;
});
A simpler approach could be to store the scroll position when the module deactivates and restore the scroll on viewAttached.
You could store the positions in some global app variable:
app.scrollPositions = app.scrollPositions || {};
app.scrollPositions[system.getModuleId(this)] = theCurrentScrollPosition;

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;
});