PDA

View Full Version : Ext.ux.window.Notification



eirik.lorentsen
30 Aug 2011, 7:23 AM
Notification extension for Ext JS 4.0.2+

Examples and instructions (http://www.eirik.net/Ext/ux/window/Demo.html)

New improved features include:

Multiple managers and notifications stacks
The static manager object is eliminated completely, allowing notifications to attach to different components using their x and y coordinates to slide in the notifications.
All eight corners and edges of document/manager can be used: 'tl', 'tr', 'br', 'bl', 't', 'l', 'b', 'r'.
Both x and y axis can be used on corners. Notifications can slide in sideways.
When a notification is closed any notifications above it slide down automatically.
Hovering the mouse over the notification delays auto closing.
Easy customization of css, animations, delays, spacings/padding etc.
Find the latest version on GitHub (https://github.com/EirikLorentsen/Ext.ux.window.Notification)

Or simply paste this code into a Notification.js file:


/*
* Notification extension for Ext JS 4.0.2+
* Version: 2.1.2
*
* Copyright (c) 2011 Eirik Lorentsen (http://www.eirik.net/)
*
* Follow project on GitHub: https://github.com/EirikLorentsen/Ext.ux.window.Notification
*
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://opensource.org/licenses/GPL-3.0) licenses.
*
*/


Ext.define('Ext.ux.window.Notification', {
extend: 'Ext.window.Window',
alias: 'widget.uxNotification',


cls: 'ux-notification-window',
autoClose: true,
autoHeight: true,
plain: false,
draggable: false,
shadow: false,
focus: Ext.emptyFn,


// For alignment and to store array of rendered notifications. Defaults to document if not set.
manager: null,


useXAxis: false,


// Options: br, bl, tr, tl, t, l, b, r
position: 'br',


// Pixels between each notification
spacing: 6,


// Pixels from the managers borders to start the first notification
paddingX: 30,
paddingY: 10,


slideInAnimation: 'easeIn',
slideBackAnimation: 'bounceOut',
slideInDuration: 1500,
slideBackDuration: 1000,
hideDuration: 500,
autoCloseDelay: 7000,
stickOnClick: true,
stickWhileHover: true,


// Private. Do not override!
isHiding: false,
isFading: false,
destroyAfterHide: false,
closeOnMouseOut: false,


// Caching coordinates to be able to align to final position of siblings being animated
xPos: 0,
yPos: 0,


statics: {
defaultManager: {
el: null
}
},


initComponent: function() {
var me = this;


// Backwards compatibility
if (Ext.isDefined(me.corner)) {
me.position = me.corner;
}
if (Ext.isDefined(me.slideDownAnimation)) {
me.slideBackAnimation = me.slideDownAnimation;
}
if (Ext.isDefined(me.autoDestroyDelay)) {
me.autoCloseDelay = me.autoDestroyDelay;
}
if (Ext.isDefined(me.autoHideDelay)) {
me.autoCloseDelay = me.autoHideDelay;
}
if (Ext.isDefined(me.autoHide)) {
me.autoClose = me.autoHide;
}
if (Ext.isDefined(me.slideInDelay)) {
me.slideInDuration = me.slideInDelay;
}
if (Ext.isDefined(me.slideDownDelay)) {
me.slideBackDuration = me.slideDownDelay;
}
if (Ext.isDefined(me.fadeDelay)) {
me.hideDuration = me.fadeDelay;
}


// 'bc', lc', 'rc', 'tc' compatibility
me.position = me.position.replace(/c/, '');


me.updateAlignment(me.position);


me.setManager(me.manager);


me.callParent(arguments);
},


onRender: function() {
var me = this;
me.callParent(arguments);


me.el.hover(
function () {
me.mouseIsOver = true;
},
function () {
me.mouseIsOver = false;
if (me.closeOnMouseOut) {
me.closeOnMouseOut = false;
me.close();
}
},
me
);


},

updateAlignment: function (position) {
var me = this;


switch (position) {
case 'br':
me.paddingFactorX = -1;
me.paddingFactorY = -1;
me.siblingAlignment = "br-br";
if (me.useXAxis) {
me.managerAlignment = "bl-br";
} else {
me.managerAlignment = "tr-br";
}
break;
case 'bl':
me.paddingFactorX = 1;
me.paddingFactorY = -1;
me.siblingAlignment = "bl-bl";
if (me.useXAxis) {
me.managerAlignment = "br-bl";
} else {
me.managerAlignment = "tl-bl";
}
break;
case 'tr':
me.paddingFactorX = -1;
me.paddingFactorY = 1;
me.siblingAlignment = "tr-tr";
if (me.useXAxis) {
me.managerAlignment = "tl-tr";
} else {
me.managerAlignment = "br-tr";
}
break;
case 'tl':
me.paddingFactorX = 1;
me.paddingFactorY = 1;
me.siblingAlignment = "tl-tl";
if (me.useXAxis) {
me.managerAlignment = "tr-tl";
} else {
me.managerAlignment = "bl-tl";
}
break;
case 'b':
me.paddingFactorX = 0;
me.paddingFactorY = -1;
me.siblingAlignment = "b-b";
me.useXAxis = 0;
me.managerAlignment = "t-b";
break;
case 't':
me.paddingFactorX = 0;
me.paddingFactorY = 1;
me.siblingAlignment = "t-t";
me.useXAxis = 0;
me.managerAlignment = "b-t";
break;
case 'l':
me.paddingFactorX = 1;
me.paddingFactorY = 0;
me.siblingAlignment = "l-l";
me.useXAxis = 1;
me.managerAlignment = "r-l";
break;
case 'r':
me.paddingFactorX = -1;
me.paddingFactorY = 0;
me.siblingAlignment = "r-r";
me.useXAxis = 1;
me.managerAlignment = "l-r";
break;
}
},

getXposAlignedToManager: function () {
var me = this;


var xPos = 0;


// Avoid error messages if the manager does not have a dom element
if (me.manager && me.manager.el && me.manager.el.dom) {
if (!me.useXAxis) {
// Element should already be aligned vertically
return me.el.getLeft();
} else {
// Using getAnchorXY instead of getTop/getBottom should give a correct placement when document is used
// as the manager but is still 0 px high. Before rendering the viewport.
if (me.position == 'br' || me.position == 'tr' || me.position == 'r') {
xPos += me.manager.el.getAnchorXY('r')[0];
xPos -= (me.el.getWidth() + me.paddingX);
} else {
xPos += me.manager.el.getAnchorXY('l')[0];
xPos += me.paddingX;
}
}
}


return xPos;
},


getYposAlignedToManager: function () {
var me = this;


var yPos = 0;


// Avoid error messages if the manager does not have a dom element
if (me.manager && me.manager.el && me.manager.el.dom) {
if (me.useXAxis) {
// Element should already be aligned horizontally
return me.el.getTop();
} else {
// Using getAnchorXY instead of getTop/getBottom should give a correct placement when document is used
// as the manager but is still 0 px high. Before rendering the viewport.
if (me.position == 'br' || me.position == 'bl' || me.position == 'b') {
yPos += me.manager.el.getAnchorXY('b')[1];
yPos -= (me.el.getHeight() + me.paddingY);
} else {
yPos += me.manager.el.getAnchorXY('t')[1];
yPos += me.paddingY;
}
}
}


return yPos;
},


getXposAlignedToSibling: function (sibling) {
var me = this;


if (me.useXAxis) {
if (me.position == 'tl' || me.position == 'bl' || me.position == 'l') {
// Using sibling's width when adding
return (sibling.xPos + sibling.el.getWidth() + sibling.spacing);
} else {
// Using own width when subtracting
return (sibling.xPos - me.el.getWidth() - me.spacing);
}
} else {
return me.el.getLeft();
}


},


getYposAlignedToSibling: function (sibling) {
var me = this;


if (me.useXAxis) {
return me.el.getTop();
} else {
if (me.position == 'tr' || me.position == 'tl' || me.position == 't') {
// Using sibling's width when adding
return (sibling.yPos + sibling.el.getHeight() + sibling.spacing);
} else {
// Using own width when subtracting
return (sibling.yPos - me.el.getHeight() - sibling.spacing);
}
}
},


getNotifications: function (alignment) {
var me = this;


if (!me.manager.notifications[alignment]) {
me.manager.notifications[alignment] = [];
}


return me.manager.notifications[alignment];
},


setManager: function (manager) {
var me = this;


me.manager = manager;


if (typeof me.manager == 'string') {
me.manager = Ext.getCmp(me.manager);
}


// If no manager is provided or found, then the static object is used and the el property pointed to the body document.
if (!me.manager) {
me.manager = me.statics().defaultManager;


if (!me.manager.el) {
me.manager.el = Ext.getBody();
}
}

if (typeof me.manager.notifications == 'undefined') {
me.manager.notifications = {};
}
},

beforeShow: function () {
var me = this;


if (me.stickOnClick) {
if (me.body && me.body.dom) {
Ext.fly(me.body.dom).on('click', function () {
me.cancelAutoClose();
me.addCls('notification-fixed');
}, me);
}
}


if (me.autoClose) {
me.task = new Ext.util.DelayedTask(me.doAutoClose, me);
me.task.delay(me.autoCloseDelay);
}


// Shunting offscreen to avoid flicker
me.el.setX(-10000);
me.el.setOpacity(1);

},


afterShow: function () {
var me = this;


me.callParent(arguments);


var notifications = me.getNotifications(me.managerAlignment);


if (notifications.length) {
me.el.alignTo(notifications[notifications.length - 1].el, me.siblingAlignment, [0, 0]);
me.xPos = me.getXposAlignedToSibling(notifications[notifications.length - 1]);
me.yPos = me.getYposAlignedToSibling(notifications[notifications.length - 1]);
} else {
me.el.alignTo(me.manager.el, me.managerAlignment, [(me.paddingX * me.paddingFactorX), (me.paddingY * me.paddingFactorY)], false);
me.xPos = me.getXposAlignedToManager();
me.yPos = me.getYposAlignedToManager();
}


Ext.Array.include(notifications, me);


// Repeating from coordinates makes sure the windows does not flicker into the center of the viewport during animation
me.el.animate({
from: {
x: me.el.getX(),
y: me.el.getY()
},
to: {
x: me.xPos,
y: me.yPos,
opacity: 1
},
easing: me.slideInAnimation,
duration: me.slideInDuration,
dynamic: true
});


},

slideBack: function () {
var me = this;


var notifications = me.getNotifications(me.managerAlignment);
var index = Ext.Array.indexOf(notifications, me)


// Not animating the element if it already started to hide itself or if the manager is not present in the dom
if (!me.isHiding && me.el && me.manager && me.manager.el && me.manager.el.dom && me.manager.el.isVisible()) {


if (index) {
me.xPos = me.getXposAlignedToSibling(notifications[index - 1]);
me.yPos = me.getYposAlignedToSibling(notifications[index - 1]);
} else {
me.xPos = me.getXposAlignedToManager();
me.yPos = me.getYposAlignedToManager();
}


me.stopAnimation();


me.el.animate({
to: {
x: me.xPos,
y: me.yPos
},
easing: me.slideBackAnimation,
duration: me.slideBackDuration,
dynamic: true
});
}
},


cancelAutoClose: function() {
var me = this;


if (me.autoClose) {
me.task.cancel();
}
},


doAutoClose: function () {
var me = this;


if (!(me.stickWhileHover && me.mouseIsOver)) {
// Close immediately
me.close();
} else {
// Delayed closing when mouse leaves the component.
me.closeOnMouseOut = true;
}
},


removeFromManager: function () {
var me = this;


if (me.manager) {
var notifications = me.getNotifications(me.managerAlignment);
var index = Ext.Array.indexOf(notifications, me);
if (index != -1) {
// Requires Ext JS 4.0.2
Ext.Array.erase(notifications, index, 1);


// Slide "down" all notifications "above" the hidden one
for (;index < notifications.length; index++) {
notifications[index].slideBack();
}
}
}
},


hide: function () {
var me = this;


if (me.isHiding) {
if (!me.isFading) {
me.callParent(arguments);
// Must come after callParent() since it will pass through hide() again triggered by destroy()
me.isHiding = false;
}
} else {
// Must be set right away in case of double clicks on the close button
me.isHiding = true;
me.isFading = true;


me.cancelAutoClose();


if (me.el) {
me.el.fadeOut({
opacity: 0,
easing: 'easeIn',
duration: me.hideDuration,
remove: me.destroyAfterHide,
listeners: {
afteranimate: function () {
me.isFading = false;
me.removeCls('notification-fixed');
me.removeFromManager();
me.hide();
}
}
});
}
}


return me;
},


destroy: function () {
var me = this;
if (!me.hidden) {
me.destroyAfterHide = true;
me.hide();
} else {
me.callParent(arguments);
}
}


});

shadowman1024
30 Aug 2011, 10:47 AM
thanks a lot for this. Excellent work

mitchellsimoens
30 Aug 2011, 12:43 PM
Very nice! Love the bounce effects!

kennedyt
30 Aug 2011, 2:09 PM
Very good!

Ekambos
31 Aug 2011, 5:05 AM
You saved my day :)

thomaschang
1 Sep 2011, 5:36 AM
i found it got error message at line 292 within IE7 & IE8

eirik.lorentsen
1 Sep 2011, 7:05 AM
thomaschang,

Thanx for reporting that bug! The Array.indexOf method that I was using is not universally implemented and failed in older IE versions. I replaced my array manipulations with the Ext.Array library methods and now it seems to work fine in IE8. I have updated the source in my original post.

I have testet version 1.1 in the following browsers without any issues:
win7: FF 6.0.1, IE8, IE9, Chrome 13, Opera 11.50
android2.3.3: Stock browser, Dolphin HD 6.1.0, FF 6.0, Opera 11.10

thomaschang
1 Sep 2011, 6:45 PM
when the notification is designed to show before creating a new ext.window , the notification will be put behind the new window, then you cannot see it wholly or partially

jmaia
2 Sep 2011, 7:25 AM
Great stuff, just what I was looking for. :D

Is there a way to make the notification window 'sticky' when the user hovers the mouse on the window and then release it when the user hovers out ? Like in growl ?

Regards,

Joao Maia

kennedyt
2 Sep 2011, 2:05 PM
Sorry, but how use? Thanks.

jmaia
5 Sep 2011, 12:40 AM
Do a 'View Source' on the examples page and you can see several ways of using it.

Regards,

jm

kennedyt
5 Sep 2011, 8:12 AM
Thanks for the reply. But the site does not access here. :s

jmaia
5 Sep 2011, 8:16 AM
Here's an example:


Ext.create('widget.uxNotification', {
corner: 'tr',
manager: 'instructions',
//iconCls: 'notification-icon-information',
title: 'Test',
html: 'Test message',
autoDestroyDelay: 4000,
slideInDelay: 500,
slideDownDelay: 500,
slideInAnimation: 'bounceOut',
slideDownAnimation: 'easeIn'
}).show();

I'm not using any icon, if you want to use an icon you have to define it in the css.

Regards,

jm

kennedyt
5 Sep 2011, 8:25 AM
Thank you for the example :)

wm003
8 Sep 2011, 11:13 PM
B) Great! Thanks for sharing

atian25
11 Sep 2011, 9:49 PM
good job!!!

a small suggest: add some ext-like doc tags so that jsduck(https://github.com/senchalabs/jsduck) can gen doc

twaindev
12 Sep 2011, 8:03 AM
Great job!!

Thanks.

eirik.lorentsen
13 Sep 2011, 5:33 AM
jmaia,

I have created a new version 1.2 including your feature suggestion.

There are now two new config options: stickOnClick and stickWhileHover
They both default to true.

The stickOnClick enables/disables the pinning of the notification if clicked on.
The stickWhileHover enables/disables temporary pinning of the notification while the mouse hovers over it.

I have updated the demo page and also added an alternative styling to it:
http://www.eirik.net/Ext/ux/window/Notification.html

jmaia
13 Sep 2011, 5:43 AM
Erik,

It's super cool ! :D

Thanks for the update,

jm

kennedyt
13 Sep 2011, 6:47 AM
Uowwww! =D>

eirik.lorentsen
13 Sep 2011, 7:17 AM
Minor changes on how the component is destroyed.

kreeve_ctisn
13 Sep 2011, 9:48 AM
Hi,thanks for the nice plugin/extension..

for future versions can you remove the title default as would be good to not have to pass title: null or other such to overwrite the component's version "Notification"

twaindev
13 Sep 2011, 11:43 AM
Thanks for the updates. I really like the new style.

fancing
17 Sep 2011, 11:40 PM
Good extension, i added it to my site.

loiane
21 Sep 2011, 5:38 AM
Thanks for sharing!

SMMJ_Dev
25 Sep 2011, 9:46 AM
Just an FYI,

I was able to get your light style for notifications to work with all browsers.

I am now calling your notification like below in order to use the ui property that is meant for different component styles.


Ext.widget('uxNotification',{
corner:'tr',
ui:'light',
closable: true,
title: '',
useXAxis: true,
stickOnClick:true,
resizable:false,
iconCls: 'ux-notification-icon-information',
html: 'Using document as manager. No title and closable: false. Entering from the tr corner using x-axis.'
}).show();


After that you have to have the style setup in either ext-all.css or create your own style. I created my own style script instead of ext-all.css just because I have changed alot of colors etc.

Anyways, place this inside of your scss script to create the styles for you. This is the custom scss mixin I created for developing the notification styles:


@mixin extjs-notification-window-ui(
$ui,
$textAlignment:center,
$padding:15px 5px 15px 5px,
$width:200px,
$bodyBackgroundColor:#FFFFFF,
$windowBackgroundColor:#FFFFFF,
$headerBackgroundColor:null,
$bodyBorder:null,
$windowImage:null,
$headerBorder:null
){
@if $ui == null {
$ui:"";
}
@else {
$ui:-#{$ui};
}
.ux-notification-window .x-window-body#{$ui}{
text-align:$textAlignment;
padding:$padding;
width:$width;
background-color:$bodyBackgroundColor;
border:$bodyBorder;
}
.ux-notification-icon-information{
background-image:url('icon_info.png');
}
.ux-notification-icon-error{
background-image:url('icon_error.png');
}
.x-window-header#{$ui}-top{
background-color:$headerBackgroundColor;
border:$headerBorder;
}
body .ux-notification-window{
background-color:$windowBackgroundColor;
background-image:$windowImage;
}
.x-nlg .x-window-header#{$ui}-top-mc, .x-nlg .x-window#{$ui}-mc{
background-color:$windowBackgroundColor;
}
.x-nlg .x-window#{$ui}-mc{
background-color:$bodyBackgroundColor;
background-image:$windowImage;
}
}


Then inside of your scss file add the call to make the regular style and the "light" style:


@include extjs-notification-window-ui(null,center,15px 5px 15px 5px,200px,null,null,null,null,null);
@include extjs-notification-window-ui("light",center,15px 5px 18px 5px,200px,transparent,#FFFFFF,transparent,0px solid white,url('fader.png'),0px none transparent);
@include extjs-window-ui($ui-label:"light",$ui-border-radius:$window-border-radius,$ui-border-color:$window-border-color,$ui-inner-border-color:$window-inner-border-color,
$ui-header-color:$window-header-color,$ui-body-border-color:$window-body-border-color,$ui-body-background-color:$window-body-background-color,
$ui-body-color:$window-body-color,$ui-background-color:#FFFFFF
);


If you just want the CSS w/o doing the compiling etc, this is what the CSS produces:


/* line 69, ../sass/ext-portal-all.scss */
.ux-notification-window .x-window-body {
text-align: center;
padding: 15px 5px 15px 5px;
width: 200px;
background-color: null;
border: null;
}


/* line 76, ../sass/ext-portal-all.scss */
.ux-notification-icon-information {
background-image: url("icon_info.png");
}


/* line 79, ../sass/ext-portal-all.scss */
.ux-notification-icon-error {
background-image: url("icon_error.png");
}


/* line 82, ../sass/ext-portal-all.scss */
.x-window-header-top {
background-color: null;
border: null;
}


/* line 86, ../sass/ext-portal-all.scss */
body .ux-notification-window {
background-color: null;
background-image: null;
}


/* line 90, ../sass/ext-portal-all.scss */
.x-nlg .x-window-header-top-mc, .x-nlg .x-window-mc {
background-color: null;
}


/* line 93, ../sass/ext-portal-all.scss */
.x-nlg .x-window-mc {
background-color: null;
background-image: null;
}


/* line 69, ../sass/ext-portal-all.scss */
.ux-notification-window .x-window-body-light {
text-align: center;
padding: 15px 5px 18px 5px;
width: 200px;
background-color: transparent;
border: 0px solid white;
}


/* line 76, ../sass/ext-portal-all.scss */
.ux-notification-icon-information {
background-image: url("icon_info.png");
}


/* line 79, ../sass/ext-portal-all.scss */
.ux-notification-icon-error {
background-image: url("icon_error.png");
}


/* line 82, ../sass/ext-portal-all.scss */
.x-window-header-light-top {
background-color: transparent;
border: 0px none transparent;
}


/* line 86, ../sass/ext-portal-all.scss */
body .ux-notification-window {
background-color: white;
background-image: url("fader.png");
}


/* line 90, ../sass/ext-portal-all.scss */
.x-nlg .x-window-header-light-top-mc, .x-nlg .x-window-light-mc {
background-color: white;
}


/* line 93, ../sass/ext-portal-all.scss */
.x-nlg .x-window-light-mc {
background-color: transparent;
background-image: url("fader.png");
}


/* line 111, ../themes/stylesheets/ext4/default/widgets/_window.scss */
.x-window-light {
border-color: #a2b1c5;
-moz-border-radius: 5px 5px 5px 5px;
-webkit-border-radius: 5px 5px 5px 5px;
-o-border-radius: 5px 5px 5px 5px;
-ms-border-radius: 5px 5px 5px 5px;
-khtml-border-radius: 5px 5px 5px 5px;
border-radius: 5px 5px 5px 5px;
-moz-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
-webkit-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
-o-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
}


/* line 58, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-window-light {
-moz-border-radius-topleft: 5px;
-webkit-border-top-left-radius: 5px;
-o-border-top-left-radius: 5px;
-ms-border-top-left-radius: 5px;
-khtml-border-top-left-radius: 5px;
border-top-left-radius: 5px;
-moz-border-radius-topright: 5px;
-webkit-border-top-right-radius: 5px;
-o-border-top-right-radius: 5px;
-ms-border-top-right-radius: 5px;
-khtml-border-top-right-radius: 5px;
border-top-right-radius: 5px;
-moz-border-radius-bottomright: 5px;
-webkit-border-bottom-right-radius: 5px;
-o-border-bottom-right-radius: 5px;
-ms-border-bottom-right-radius: 5px;
-khtml-border-bottom-right-radius: 5px;
border-bottom-right-radius: 5px;
-moz-border-radius-bottomleft: 5px;
-webkit-border-bottom-left-radius: 5px;
-o-border-bottom-left-radius: 5px;
-ms-border-bottom-left-radius: 5px;
-khtml-border-bottom-left-radius: 5px;
border-bottom-left-radius: 5px;
padding: 4px 4px 4px 4px;
border-width: 1px;
border-style: solid;
background-color: white;
}


/* line 91, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nlg .x-window-light-mc {
background-color: white;
}


/* line 104, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-light {
padding: 0 !important;
border-width: 0 !important;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
-o-border-radius: 0px;
-ms-border-radius: 0px;
-khtml-border-radius: 0px;
border-radius: 0px;
background-color: transparent;
background-position: 1000505px 1000505px;
}
/* line 147, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-light-tl,
.x-nbr .x-window-light-bl,
.x-nbr .x-window-light-tr,
.x-nbr .x-window-light-br,
.x-nbr .x-window-light-tc,
.x-nbr .x-window-light-bc,
.x-nbr .x-window-light-ml,
.x-nbr .x-window-light-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window/window-light-corners.gif');
}
/* line 168, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-light-ml,
.x-nbr .x-window-light-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window/window-light-sides.gif');
background-position: 0 0;
background-repeat: repeat-y;
}
/* line 200, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-light-mc {
padding: 0 0 0 0;
}


/* line 130, ../themes/stylesheets/ext4/default/widgets/_window.scss */
.x-window-body-light {
border-color: #a9bfd3;
border-width: 1px;
background: #dfe8f6;
color: black;
}


/* line 140, ../themes/stylesheets/ext4/default/widgets/_window.scss */
.x-window-header-light {
border-color: #a2b1c5;
zoom: 1;
}


/* line 145, ../themes/stylesheets/ext4/default/widgets/_window.scss */
.x-window-header-text-light {
color: #04468c;
font-weight: bold;
line-height: 11px;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: ignore;
cursor: default;
white-space: nowrap;
overflow: visible;
font-family: tahoma, arial, verdana, sans-serif;
font-size: 11px;
}


/* line 58, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-window-header-light-top {
-moz-border-radius-topleft: 5px;
-webkit-border-top-left-radius: 5px;
-o-border-top-left-radius: 5px;
-ms-border-top-left-radius: 5px;
-khtml-border-top-left-radius: 5px;
border-top-left-radius: 5px;
-moz-border-radius-topright: 5px;
-webkit-border-top-right-radius: 5px;
-o-border-top-right-radius: 5px;
-ms-border-top-right-radius: 5px;
-khtml-border-top-right-radius: 5px;
border-top-right-radius: 5px;
-moz-border-radius-bottomright: 0;
-webkit-border-bottom-right-radius: 0;
-o-border-bottom-right-radius: 0;
-ms-border-bottom-right-radius: 0;
-khtml-border-bottom-right-radius: 0;
border-bottom-right-radius: 0;
-moz-border-radius-bottomleft: 0;
-webkit-border-bottom-left-radius: 0;
-o-border-bottom-left-radius: 0;
-ms-border-bottom-left-radius: 0;
-khtml-border-bottom-left-radius: 0;
border-bottom-left-radius: 0;
padding: 5px 5px 0 5px;
border-width: 1px;
border-style: solid;
background-color: white;
}


/* line 91, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nlg .x-window-header-light-top-mc {
background-color: white;
}


/* line 104, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-top {
padding: 0 !important;
border-width: 0 !important;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
-o-border-radius: 0px;
-ms-border-radius: 0px;
-khtml-border-radius: 0px;
border-radius: 0px;
background-color: transparent;
background-position: 1000505px 1000000px;
}
/* line 147, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-top-tl,
.x-nbr .x-window-header-light-top-bl,
.x-nbr .x-window-header-light-top-tr,
.x-nbr .x-window-header-light-top-br,
.x-nbr .x-window-header-light-top-tc,
.x-nbr .x-window-header-light-top-bc,
.x-nbr .x-window-header-light-top-ml,
.x-nbr .x-window-header-light-top-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window-header/window-header-light-top-corners.gif');
}
/* line 168, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-top-ml,
.x-nbr .x-window-header-light-top-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window-header/window-header-light-top-sides.gif');
background-position: 0 0;
background-repeat: repeat-y;
}
/* line 200, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-top-mc {
padding: 0px 0px 0 0px;
}


/* line 58, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-window-header-light-right {
-moz-border-radius-topleft: 0;
-webkit-border-top-left-radius: 0;
-o-border-top-left-radius: 0;
-ms-border-top-left-radius: 0;
-khtml-border-top-left-radius: 0;
border-top-left-radius: 0;
-moz-border-radius-topright: 5px;
-webkit-border-top-right-radius: 5px;
-o-border-top-right-radius: 5px;
-ms-border-top-right-radius: 5px;
-khtml-border-top-right-radius: 5px;
border-top-right-radius: 5px;
-moz-border-radius-bottomright: 5px;
-webkit-border-bottom-right-radius: 5px;
-o-border-bottom-right-radius: 5px;
-ms-border-bottom-right-radius: 5px;
-khtml-border-bottom-right-radius: 5px;
border-bottom-right-radius: 5px;
-moz-border-radius-bottomleft: 0;
-webkit-border-bottom-left-radius: 0;
-o-border-bottom-left-radius: 0;
-ms-border-bottom-left-radius: 0;
-khtml-border-bottom-left-radius: 0;
border-bottom-left-radius: 0;
padding: 5px 5px 5px 0;
border-width: 1px;
border-style: solid;
background-color: white;
}


/* line 91, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nlg .x-window-header-light-right-mc {
background-color: white;
}


/* line 104, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-right {
padding: 0 !important;
border-width: 0 !important;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
-o-border-radius: 0px;
-ms-border-radius: 0px;
-khtml-border-radius: 0px;
border-radius: 0px;
background-color: transparent;
background-position: 1000005px 1000500px;
}
/* line 147, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-right-tl,
.x-nbr .x-window-header-light-right-bl,
.x-nbr .x-window-header-light-right-tr,
.x-nbr .x-window-header-light-right-br,
.x-nbr .x-window-header-light-right-tc,
.x-nbr .x-window-header-light-right-bc,
.x-nbr .x-window-header-light-right-ml,
.x-nbr .x-window-header-light-right-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window-header/window-header-light-right-corners.gif');
}
/* line 168, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-right-ml,
.x-nbr .x-window-header-light-right-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window-header/window-header-light-right-sides.gif');
background-position: 0 0;
background-repeat: repeat-y;
}
/* line 200, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-right-mc {
padding: 0px 0px 0px 0;
}


/* line 58, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-window-header-light-bottom {
-moz-border-radius-topleft: 0;
-webkit-border-top-left-radius: 0;
-o-border-top-left-radius: 0;
-ms-border-top-left-radius: 0;
-khtml-border-top-left-radius: 0;
border-top-left-radius: 0;
-moz-border-radius-topright: 0;
-webkit-border-top-right-radius: 0;
-o-border-top-right-radius: 0;
-ms-border-top-right-radius: 0;
-khtml-border-top-right-radius: 0;
border-top-right-radius: 0;
-moz-border-radius-bottomright: 5px;
-webkit-border-bottom-right-radius: 5px;
-o-border-bottom-right-radius: 5px;
-ms-border-bottom-right-radius: 5px;
-khtml-border-bottom-right-radius: 5px;
border-bottom-right-radius: 5px;
-moz-border-radius-bottomleft: 5px;
-webkit-border-bottom-left-radius: 5px;
-o-border-bottom-left-radius: 5px;
-ms-border-bottom-left-radius: 5px;
-khtml-border-bottom-left-radius: 5px;
border-bottom-left-radius: 5px;
padding: 0 5px 5px 5px;
border-width: 1px;
border-style: solid;
background-color: white;
}


/* line 91, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nlg .x-window-header-light-bottom-mc {
background-color: white;
}


/* line 104, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-bottom {
padding: 0 !important;
border-width: 0 !important;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
-o-border-radius: 0px;
-ms-border-radius: 0px;
-khtml-border-radius: 0px;
border-radius: 0px;
background-color: transparent;
background-position: 1000000px 1000505px;
}
/* line 147, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-bottom-tl,
.x-nbr .x-window-header-light-bottom-bl,
.x-nbr .x-window-header-light-bottom-tr,
.x-nbr .x-window-header-light-bottom-br,
.x-nbr .x-window-header-light-bottom-tc,
.x-nbr .x-window-header-light-bottom-bc,
.x-nbr .x-window-header-light-bottom-ml,
.x-nbr .x-window-header-light-bottom-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window-header/window-header-light-bottom-corners.gif');
}
/* line 168, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-bottom-ml,
.x-nbr .x-window-header-light-bottom-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window-header/window-header-light-bottom-sides.gif');
background-position: 0 0;
background-repeat: repeat-y;
}
/* line 200, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-bottom-mc {
padding: 0 0px 0px 0px;
}


/* line 58, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-window-header-light-left {
-moz-border-radius-topleft: 5px;
-webkit-border-top-left-radius: 5px;
-o-border-top-left-radius: 5px;
-ms-border-top-left-radius: 5px;
-khtml-border-top-left-radius: 5px;
border-top-left-radius: 5px;
-moz-border-radius-topright: 0;
-webkit-border-top-right-radius: 0;
-o-border-top-right-radius: 0;
-ms-border-top-right-radius: 0;
-khtml-border-top-right-radius: 0;
border-top-right-radius: 0;
-moz-border-radius-bottomright: 0;
-webkit-border-bottom-right-radius: 0;
-o-border-bottom-right-radius: 0;
-ms-border-bottom-right-radius: 0;
-khtml-border-bottom-right-radius: 0;
border-bottom-right-radius: 0;
-moz-border-radius-bottomleft: 5px;
-webkit-border-bottom-left-radius: 5px;
-o-border-bottom-left-radius: 5px;
-ms-border-bottom-left-radius: 5px;
-khtml-border-bottom-left-radius: 5px;
border-bottom-left-radius: 5px;
padding: 5px 0px 5px 5px;
border-width: 1px;
border-style: solid;
background-color: white;
}


/* line 91, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nlg .x-window-header-light-left-mc {
background-color: white;
}


/* line 104, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-left {
padding: 0 !important;
border-width: 0 !important;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
-o-border-radius: 0px;
-ms-border-radius: 0px;
-khtml-border-radius: 0px;
border-radius: 0px;
background-color: transparent;
background-position: 1000500px 1000005px;
}
/* line 147, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-left-tl,
.x-nbr .x-window-header-light-left-bl,
.x-nbr .x-window-header-light-left-tr,
.x-nbr .x-window-header-light-left-br,
.x-nbr .x-window-header-light-left-tc,
.x-nbr .x-window-header-light-left-bc,
.x-nbr .x-window-header-light-left-ml,
.x-nbr .x-window-header-light-left-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window-header/window-header-light-left-corners.gif');
}
/* line 168, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-left-ml,
.x-nbr .x-window-header-light-left-mr {
zoom: 1;
background-image: url('../../resources/themes/images/default/window-header/window-header-light-left-sides.gif');
background-position: 0 0;
background-repeat: repeat-y;
}
/* line 200, ../themes/stylesheets/ext4/default/mixins/_frame.scss */
.x-nbr .x-window-header-light-left-mc {
padding: 0px 0px 0px 0px;
}


/* line 166, ../themes/stylesheets/ext4/default/widgets/_window.scss */
.x-window-header-light-top {
-moz-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
-webkit-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
-o-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
}


/* line 170, ../themes/stylesheets/ext4/default/widgets/_window.scss */
.x-window-header-light-right {
-moz-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset;
-webkit-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset;
-o-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset;
box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset;
}


/* line 174, ../themes/stylesheets/ext4/default/widgets/_window.scss */
.x-window-header-light-bottom {
-moz-box-shadow: #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
-webkit-box-shadow: #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
-o-box-shadow: #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
box-shadow: #ecf2fb 0 -1px 0px 0 inset, #ecf2fb -1px 0 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
}


/* line 178, ../themes/stylesheets/ext4/default/widgets/_window.scss */
.x-window-header-light-left {
-moz-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
-webkit-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
-o-box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
box-shadow: #ecf2fb 0 1px 0px 0 inset, #ecf2fb 0 -1px 0px 0 inset, #ecf2fb 1px 0 0px 0 inset;
}


(If you are using ext-all.css then "{theme}" will be "default")

Ok, now add these files to resources/themes/images/{theme}/window/
window-light-corners.gif
window-light-sides.gif

Add these files to resources/themes/images/{theme}/window-header/
window-header-light-bottom-corners.gif
window-header-light-bottom-side.gif
window-header-light-left-corners.gif
window-header-light-left-side.gif
window-header-light-right-corners.gif
window-header-light-right-side.gif
window-header-light-top-corners.gif
window-header-light-top-side.gif

Make sure your link paths are setup correctly inside of your CSS file.

The good thing about this is that now you also have a new theme for all of your windows. Just add ui:'light' to your window config and you will have a new light style for your windows too.

http://www.djengineer.com/ExtJSExamples/images/window-light-corners.gif
(http://www.djengineer.com/ExtJSExamples/images/window-light-corners.gif)
http://www.djengineer.com/ExtJSExamples/images/window-light-sides.gif
(http://www.djengineer.com/ExtJSExamples/images/window-light-sides.gif)
http://www.djengineer.com/ExtJSExamples/images/window-header-light-bottom-corners.gif
(http://www.djengineer.com/ExtJSExamples/images/window-header-light-bottom-corners.gif)
http://www.djengineer.com/ExtJSExamples/images/window-header-light-bottom-sides.gif
(http://www.djengineer.com/ExtJSExamples/images/window-header-light-bottom-sides.gif)
http://www.djengineer.com/ExtJSExamples/images/window-header-light-left-corners.gif
(http://www.djengineer.com/ExtJSExamples/images/window-header-light-left-corners.gif)
http://www.djengineer.com/ExtJSExamples/images/window-header-light-left-sides.gif
(http://www.djengineer.com/ExtJSExamples/images/window-header-light-left-sides.gif)
http://www.djengineer.com/ExtJSExamples/images/window-header-light-right-sides.gif
(http://www.djengineer.com/ExtJSExamples/images/window-header-light-right-sides.gif)
http://www.djengineer.com/ExtJSExamples/images/window-header-light-right-corners.gif
(http://www.djengineer.com/ExtJSExamples/images/window-header-light-right-corners.gif)
http://www.djengineer.com/ExtJSExamples/images/window-header-light-top-sides.gif
(http://www.djengineer.com/ExtJSExamples/images/window-header-light-top-sides.gif)
http://www.djengineer.com/ExtJSExamples/images/window-header-light-top-corners.gif
(http://www.djengineer.com/ExtJSExamples/images/window-header-light-top-corners.gif)

SMMJ_Dev
25 Sep 2011, 10:15 AM
The above update will make the styles work across all browsers and will create a new window style too.

Here are some images from all the different browsers:

IE7
28318
IE8
28319
IE9
28320
Chrome
28321
FireFox
28322

Here is an example of the new light style for the window it creates:
http://www.djengineer.com/ExtJSExamples/images/LightWindow.png

talha06
26 Oct 2011, 2:46 AM
great job, thanks a lot for sharing.. =D>

jmaia
28 Oct 2011, 6:12 AM
Hi,

Once again congrats on a great component.

Is there a way to display the notification window from the top or bottom, centered on the available container space ?

Something like:


corner: 'bc' //(meaning 'bottom centered')

or


corner: 'tc' //(meaning 'top centered')

Would be neat because some users are not really paying much attention to what goes on on the corners of the screen, but if the box is displayed on the center, their attention is drawn to it.

Regards,

jm

EmCy90
28 Oct 2011, 7:27 AM
Couldn't blue it together can anyone upload a working example ?

jmaia
31 Oct 2011, 1:36 AM
You can go to Eirik's example page and check out the source code (do a view source). I did that and managed to get it to work perfectly.

http://www.eirik.net/Ext/ux/window/Notification.html

Regards,

jm

EmCy90
31 Oct 2011, 1:39 AM
I have already done that i can not SMMJ_Dev (http://www.sencha.com/forum/member.php?87129-SMMJ_Dev)'s
changes to work.

jmaia
31 Oct 2011, 1:44 AM
Oh, I see. I'm not using those changes in my code (just Eirik's original version), so I can't really be of much help. But do try and post what your problem is (i.e. what is happening on your side, and maybe someone can help).

regards,

jm

dan5k
2 Nov 2011, 1:08 PM
Hello and thank you for this great plugin!
Is anyone else getting this error in Firefox:
"dom.getBoundingClientRect is not a function"
which takes me to the line in ext-debug
rect = dom.getBoundingClientRect();

It may be related to the Notification window trying to get the browser dimensions....it is creating scrollbars on the page as well. Is anyone having problems like this?

Thank you,
Dan

anton0825
2 Nov 2011, 7:19 PM
Awesome!! It's work for me.
Thank you so much, eirik.lorentsen

(http://www.sencha.com/forum/member.php?310257-eirik.lorentsen)I (http://www.sencha.com/forum/member.php?310257-eirik.lorentsen) use like this.

define standard nortificaiton


Ext.define('Real.view.shop.pc.universal.StandardNotification', {
extend: 'Ext.ux.Notification',
alias: 'widget.notification',
corner: 'tr',
manager: 'real',
cls: 'ux-notification-light',
iconCls: 'ux-notification-icon-information',
stickOnClick: true,
closable: true,
title: 'information',
html: '',
slideInDelay: 800,
slideDownDelay: 1500,
resizable: false,
slideInAnimation: 'elasticIn',
slideDownAnimation: 'elasticIn',

setErrorIcon: function() {
this.iconCls = 'ux-notification-icon-error'
},
setTitle: function(title) {
this.title = title;
},
setMessage: function(message) {
this.html = message;
},

showMessage: function(message) {
this.html = message;
this.autoDestroyDelay = message.length * 150 + 3000;
this.show();
}
})


and then, use notificaiton one liner


Ext.widget('notification').showMessage('saved');

dan5k
3 Nov 2011, 8:06 AM
figured it out.
I had ...show(document)
needed to just be ....show();

Simonici
4 Nov 2011, 1:46 AM
Great, you added what was missing in the ext3 extension.
I really like the the ms-word-enhanced-Tooltip-look-alike styling (demo 2 first button)

eirik.lorentsen
6 Nov 2011, 5:31 PM
jmaia:
Nice suggestion adding center alignment. It shouldn't be too difficult to add it in a future version.

Meanwhile it should be possible to fake it relatively easy by overriding the paddingX or paddingY properties. For example to align the notification 'bc' you poll the manager's width add the notification's width then divide by two. Using the result as the paddingX value and 'bl' as corner when creating the notifications should center them.

jmaia
7 Nov 2011, 1:46 AM
Hi Eirik,

That's cool, I will try to implement it that way, as soon as I get a little free time from the project I'm working at.

Thanks for the tip.

Regards,

Joao Maia

jmaia
9 Nov 2011, 4:30 AM
Hello again Eirik,

Managed to do it following your tip, but the calculations I did for the padding were the following:


var centerPadding = (Ext.getBody().getViewSize().width - notificationBox.width) / 2;
notificationBox.paddingX = centerPadding;


Since I'm always using the browser window in my application and showing the notification windows from that browser window (and not from a child component such as a panel), this works. But I would like to know how to do it from a child panel.

Anyway, thanks for your help ! :D

Regards,

Joao Maia

Grolubao
22 Nov 2011, 11:17 PM
Hey guys,
I love the styling that Erik and you guys did for the ux-notification-light . Unfortunately I'm still using ExtJS 3.x so the styling doesn't work. Can someone provide me the same styling but to apply to a ExtJS 3.x application?

Thanks a lot!

justmyhobby
23 Nov 2011, 3:30 PM
This extension is good. However, it will be a problem if you create many notifications with different companions of corner and useXAsis within the same manager. It is because it uses only one list of notifcations for each manager. You can fix this problem by adding a list of notifications for each companion of corner & useXAxis. For example:


statics: {
defaultManager: {
notifications: {
tl: {
horizontal: [],
vertical: []
},
tr: {
horizontal: [],
vertical: []
},
...........
},
el: null
}
},


You also need to modify the respective code that access the list of notifications as follow:


me.manager.notifications[me.corner][me.useXAxis ? 'horizontal' : 'vertical']

pmiguelmartins
5 Dec 2011, 3:55 PM
Can you send me the changes to use center mode

Thanks

Pedro Miguel Martins

jmaia
6 Dec 2011, 2:06 AM
Can you send me the changes to use center mode

I did not change the Ext.ux.window.Notification component to center the message, all I did was follow Eirik's advice and set the paddingX property before showing the notification window.

So, for example, let's say I have a generic function show:


show: function (title, msg, type, time) {
var notificationBox = Ext.create('widget.uxNotification', {
corner: 'tl',
title: title,
html: msg,
autoDestroyDelay: time,
slideInDelay: 500,
slideDownDelay: 500,
slideInAnimation: 'bounceOut',
slideDownAnimation: 'easeIn',
cls: 'ux-notification-light',
width: 400
});

var centerPadding = (Ext.getBody().getViewSize().width - notificationBox.width) / 2;
notificationBox.paddingX = centerPadding;

notificationBox.show();
}

The important bit for centering the window here are the corner: 'tl' and the lines where the centerPadding value is calculated and where I'm applying that value to the paddingX property.

Please note that, as I said on a previous post, this works for me because all my notification windows are spawned from the main browser document window and not from a child panel. If you wanted to center the notification on a child panel instead of the document window, you'd probably have to calculate the padding in a different way.

Hope that helped.

Joao Maia

pmiguelmartins
6 Dec 2011, 2:44 AM
Thanks


Pedro Martins

crealivres
16 Dec 2011, 2:18 PM
Hello and thank you for this great plugin!
Is anyone else getting this error in Firefox:
"dom.getBoundingClientRect is not a function"
which takes me to the line in ext-debug
rect = dom.getBoundingClientRect();

It may be related to the Notification window trying to get the browser dimensions....it is creating scrollbars on the page as well. Is anyone having problems like this?

Thank you,
Dan

same for me on chrome and firefox
dom.getBoundingClientRect is not a function

on ie, the same fx causes an error some lines above:
style = dom.style;
overflow = style.overflow;

==> resolved replace .show(document) by .show()

crealivres
16 Dec 2011, 3:14 PM
how to fix zindex to keep notification windows on the top ?

eirik.lorentsen
21 Dec 2011, 10:23 AM
crealivres:
I have created a alwaysOnTop controller that you can use to keep the notifications always on top.

See:
http://www.sencha.com/forum/showthread.php?163870-Ext.ux.window.AlwaysOnTo&p=696264#post696264

Or:
http://www.eirik.net/Ext/ux/window/AlwaysOnTop.html

After you add the controller you just put alwaysOnTop: true in the notification's config or in the class definition in the Notification.js file, and then the notification will stay on top of everything else.

basememara
2 Jan 2012, 10:44 AM
Nice work!! I hope this makes it into the framework. This is a huge head start!

hpsam
4 Jan 2012, 1:54 AM
Thanks for this extension.

Just one thing, addClass is deprecated so use addCls in cancelAutoDestroy.


cancelAutoDestroy: function() {
var me = this;
me.addCls('notification-fixed');

hpsam
4 Jan 2012, 4:55 AM
Thanks for this extension.

I've done some improvements / modifications for my needs, if it can be useful to others or integrated to the extension.


Change AddClass to AddCls in cancelAutoDestroy,
Add multi positions notifications in one manager (use getNotifications),
No addCls('notification-fixed') when the notification is detroyed,
To avoid errors, beforedestroy of manager, destroy all associated notifications.



/*
* Hpsam:
* - Change AddClass to AddCls in cancelAutoDestroy,
* - Add multi positions notifications in one manager (use getNotifications),
* - No addCls('notification-fixed') when the notification is detroyed,
* - To avoid errors, beforedestroy of manager, destroy all associated notifications.
*/
/*
* Notification / Toastwindow extension for Ext JS 4.x
*
* Copyright (c) 2011 Eirik Lorentsen (http://www.eirik.net/)
*
* Examples and documentation at: http://www.eirik.net/Ext/ux/window/Notification.html
*
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* Version: 1.3
* Last changed date: 2011-09-13
*/
Ext.define('Ext.ux.window.Notification', {
extend: 'Ext.window.Window',
alias: 'widget.uxNotification',

title: 'Notification',

cls: 'ux-notification-window',
autoDestroy: true,
autoHeight: true,
plain: false,
draggable: false,
shadow: false,
focus: Ext.emptyFn,

// For alignment and to store array of rendered notifications. Defaults to document if not set.
manager: null,

useXAxis: false,

// Options: br, bl, tr, tl
corner: 'br',

// Pixels between each notification
spacing: 6,

// Pixels from the managers borders to start the first notification
paddingX: 30,
paddingY: 10,

slideInAnimation: 'easeIn',
slideDownAnimation: 'bounceOut',
autoDestroyDelay: 7000,
slideInDelay: 1500,
slideDownDelay: 1000,
fadeDelay: 500,
stickOnClick: true,
stickWhileHover: true,

// Private. Do not override!
underDestruction: false,
readyToDestroy: false,
// Caching position coordinate to avoid windows overlapping when fading in simultaneously
xPos: 0,
yPos: 0,

statics: {
defaultManager: {
notifications: {},
el: null
}
},

initComponent: function() {
var me = this;

me.callParent(arguments);

switch (me.corner) {
case 'br':
me.paddingFactorX = -1;
me.paddingFactorY = -1;
me.siblingAlignment = "br-br";
if (me.useXAxis) {
me.managerAlignment = "bl-br";
} else {
me.managerAlignment = "tr-br";
}
break;
case 'bl':
me.paddingFactorX = 1;
me.paddingFactorY = -1;
me.siblingAlignment = "bl-bl";
if (me.useXAxis) {
me.managerAlignment = "br-bl";
} else {
me.managerAlignment = "tl-bl";
}
break;
case 'tr':
me.paddingFactorX = -1;
me.paddingFactorY = 1;
me.siblingAlignment = "tr-tr";
if (me.useXAxis) {
me.managerAlignment = "tl-tr";
} else {
me.managerAlignment = "br-tr";
}
break;
case 'tl':
me.paddingFactorX = 1;
me.paddingFactorY = 1;
me.siblingAlignment = "tl-tl";
if (me.useXAxis) {
me.managerAlignment = "tr-tl";
} else {
me.managerAlignment = "bl-tl";
}
break;
}

if (typeof me.manager == 'string') {
me.manager = Ext.getCmp(me.manager);
}

// If no manager is provided or found, then the static object is used and the el property pointed to the body document.
if (!me.manager) {
me.manager = me.statics().defaultManager;

if (!me.manager.el) {
me.manager.el = Ext.getBody();
}
} else if (!me.manager.destroyNotifications) {
me.manager.destroyNotifications = function(manager){
Ext.Object.each(manager.notifications, function(alignment, notifications){
Ext.Array.each(notifications, function(notification) {
notification.destroy();
});
});
}
me.manager.on('beforedestroy', me.manager.destroyNotifications, me.manager);
}

if (typeof me.manager.notifications == 'undefined') {
me.manager.notifications = {};
}
},

getNotifications: function() {
var alignment = this.managerAlignment
notifs = this.manager.notifications;
if (!notifs[alignment]) {
notifs[alignment] = [];
}
return notifs[alignment];
},

onRender: function() {
var me = this;

me.callParent(arguments);

if (me.stickOnClick) {
if (me.body && me.body.dom) {
Ext.fly(me.body.dom).on('click', me.cancelAutoDestroy, me);
}
}

if (me.autoDestroy) {
me.task = new Ext.util.DelayedTask(me.doAutoDestroy, me);
me.task.delay(me.autoDestroyDelay);
}

me.el.hover(
function () {
me.mouseIsOver = true;
},
function () {
me.mouseIsOver = false;
},
me
);

},

getXposAlignedToManager: function () {
var me = this;

var xPos = 0;

if (me.corner == 'br' || me.corner == 'tr') {
xPos += me.manager.el.getRight();
xPos -= (me.el.getWidth() + me.paddingX);
} else {
xPos += me.manager.el.getLeft();
xPos += me.paddingX;
}

return xPos;
},

getYposAlignedToManager: function () {
var me = this;

var yPos = 0;

if (me.corner == 'br' || me.corner == 'bl') {
yPos += me.manager.el.getBottom();
yPos -= (me.el.getHeight() + me.paddingY);
} else {
yPos += me.manager.el.getTop();
yPos += me.paddingY;
}

return yPos;
},

getXposAlignedToSibling: function (sibling) {
var me = this;

if (me.useXAxis) {
if (me.corner == 'tl' || me.corner == 'bl') {
// Using sibling's width when adding
return (sibling.xPos + sibling.el.getWidth() + sibling.spacing);
} else {
// Using own width when subtracting
return (sibling.xPos - me.el.getWidth() - me.spacing);
}
} else {
return me.el.getLeft();
}

},

getYposAlignedToSibling: function (sibling) {
var me = this;

if (me.useXAxis) {
return me.el.getTop();
} else {
if (me.corner == 'tr' || me.corner == 'tl') {
// Using sibling's width when adding
return (sibling.yPos + sibling.el.getHeight() + sibling.spacing);
} else {
// Using own width when subtracting
return (sibling.yPos - me.el.getHeight() - sibling.spacing);
}
}
},

beforeShow: function () {
var me = this,
notifications = me.getNotifications();

if (notifications.length) {
var lastNotif = notifications[notifications.length - 1];
me.el.alignTo(lastNotif.el, me.siblingAlignment, [0, 0]);
me.xPos = me.getXposAlignedToSibling(lastNotif);
me.yPos = me.getYposAlignedToSibling(lastNotif);
} else {
me.el.alignTo(me.manager.el, me.managerAlignment, [(me.paddingX * me.paddingFactorX), (me.paddingY * me.paddingFactorY)]);
me.xPos = me.getXposAlignedToManager();
me.yPos = me.getYposAlignedToManager();
}

Ext.Array.include(notifications, me);

me.el.animate({
to: {
x: me.xPos,
y: me.yPos
},
easing: me.slideInAnimation,
duration: me.slideInDelay,
dynamic: true
});

},

slideDown: function () {
var me = this;

var notifications = me.getNotifications(),
index = Ext.Array.indexOf(notifications, me)

// Not animating the element if it already started to destroy itself
if (!me.underDestruction && me.el) {

if (index) {
me.xPos = me.getXposAlignedToSibling(notifications[index - 1]);
me.yPos = me.getYposAlignedToSibling(notifications[index - 1]);
} else {
me.xPos = me.getXposAlignedToManager();
me.yPos = me.getYposAlignedToManager();
}

me.el.animate({
to: {
x: me.xPos,
y: me.yPos
},
easing: me.slideDownAnimation,
duration: me.slideDownDelay,
dynamic: true
});
}
},

cancelAutoDestroy: function() {
var me = this;
// No AddCls when called from destroy
!me.underDestruction && me.addCls('notification-fixed');
if (me.autoDestroy) {
me.task.cancel();
me.autoDestroy = false;
}
},

doAutoDestroy: function () {
var me = this;

/* Delayed destruction when mouse leaves the component.
Doing this before me.mouseIsOver is checked below to avoid a race condition while resetting event handlers */
me.el.hover(
function () {
},
function () {
me.destroy();
},
me
);

if (!(me.stickWhileHover && me.mouseIsOver)) {
// Destroy immediately
me.destroy();
}
},

listeners: {
'beforehide': function (me, eOpts) {
if (!me.underDestruction) {
// Force window to animate and destroy, instead of hiding
me.destroy();
return false;
}
}
},

destroy: function () {
var me = this;

// Avoids starting the last animation on an element already underway with its destruction
if (!me.underDestruction) {

me.underDestruction = true;

me.cancelAutoDestroy();
me.stopAnimation();

me.el.animate({
to: {
opacity: 0
},
easing: 'easeIn',
duration: me.fadeDelay,
dynamic: true,
listeners: {
afteranimate: function () {

var notifications = me.getNotifications(),
index = Ext.Array.indexOf(notifications, me);
if (index != -1) {
Ext.Array.erase(notifications, index, 1);

// Slide "down" all notifications "above" the destroyed one
for (;index < notifications.length; index++) {
notifications[index].slideDown();
}
}
me.readyToDestroy = true;
me.destroy();
}
}
});
}

// After animation is complete the component may be destroyed
if (me.readyToDestroy) {
this.callParent(arguments);
}
}

});


/* Changelog:
*
* 2011-09-01 - 1.1: Bugfix. Array.indexOf not universally implemented, causing errors in IE<=8. Replaced with Ext.Array.indexOf.
* 2011-09-12 - 1.2: Added config options: stickOnClick and stickWhileHover
* 2011-09-13 - 1.3: Cleaned up component destruction
*
*/

ontho
11 Jan 2012, 5:57 AM
Thanks for this entension! It works fine in a viewport, however on a "normal" html-page which can be scrolled horizontally and vertically, the notifications might not be visible to the user (for example: Use "tr" on a scrolled-down browser-window). Any idea how to solve this?

Psychokrameur
10 Feb 2012, 8:05 AM
jmaia:
Nice suggestion adding center alignment. It shouldn't be too difficult to add it in a future version.

Meanwhile it should be possible to fake it relatively easy by overriding the paddingX or paddingY properties. For example to align the notification 'bc' you poll the manager's width add the notification's width then divide by two. Using the result as the paddingX value and 'bl' as corner when creating the notifications should center them.

One more uxNotification fan and user which is interested on support off center functionnality ('tc' and 'bc') :)

eirik.lorentsen
10 Feb 2012, 9:41 AM
One more uxNotification fan and user which is interested on support off center functionnality ('tc' and 'bc') :)

I have been working on a new version with all the suggested improvments including center alignment. I'm expecting to have it ready pretty soon!

Psychokrameur
10 Feb 2012, 2:18 PM
Joy !!!

Thanks Eirik :)

ashokvilvanathan
19 Feb 2012, 11:29 PM
Thanks for the extension. Am getting an error that says 'Ext.Array.erase is not a function'. Could anyone help...

lorezyra
20 Feb 2012, 10:12 PM
I'm loving these new features! Can't wait to consume them in my next project.=D>

eirik.lorentsen
6 Mar 2012, 12:09 PM
The wait is over! Version 2.0 is here!

The new features/improvements are as following:

Renamed some properties ending with "Delay" to the more correct: "Duration".
Moved the hiding animation out of destruction and into hide.
Renamed the corresponding "destroy" properties to "hide".
(Hpsam) Changed addClass to addCls.
(Hpsam) Avoiding setting 'notification-fixed' when auto hiding.
(Justmyhobby) Using separate arrays to enable managers to mix alignments.
(Kreeve_ctisn) Removed default title.
(Jmaia) Center of edges can be used for positioning. Renamed corner property to position.
(Hpsam) Hiding or destroying manager does not cause errors.
The most requested feature was the centering of the notifications. This can now be done through the position property which is the 2.0 equivalent of the corner property.
Set position to 'l', 'r', 't' or 'b' for left, right, top or bottom alignment. I also included 'lc', 'rc', 'tc' and 'bc' as equivalent options as "left center" probably will sound logical to most users. Se the demo (http://www.eirik.net/Ext/ux/window/Notification.html) for examples.

I figured it was a good idea to rename corner to position since the sides now are included. Position is also the term used in the framework. There is also a backwards compatibility layer so it is not strictly neccessary to rename the properties when upgrading.

For those who do wish to use the correct property names the changes from 1.3 are:
corner = position
slideDownAnimation = slideBackAnimation
autoDestroyDelay = autoHideDelay
slideInDelay = slideInDuration
slideDownDelay = slideBackDuration
fadeDelay = hideDuration
autoDestroy = autoHide
(autoDestroy is a property on the AbstractContainer component so there used to be an unfortunate overlap here)

The updated source can be found on the demo (http://www.eirik.net/Ext/ux/window/Notification.html) page or the first post in this thread.

Psychokrameur
7 Mar 2012, 2:02 AM
Oh yes!

Thanks a lot Eric, very good job. Changes well documented.
I will change the version right now in my app!

ldonofrio
23 Mar 2012, 5:46 AM
eirik.lorentsen (http://www.sencha.com/forum/member.php?310257-eirik.lorentsen), thanks for the great UX!

I need to destroy the notifications after hide so i'm trying to update the plugin to do that, but i can't, i got a lot of errors doing me.destroy after "hide method".

Can anyone give some advice? What i'm missing here? There is any purpose for hidding the windows and leaving in the dom?

Thanks again for the good work!

dmurat
5 Apr 2012, 10:26 AM
Hi,

I'm having problems with running this extension under Ext 4.1.0.RC2. Basically, I have a button which shows and hides notification, where notification is instantiated on first show and reused later for consecutive show() calls. On first notification.show(), everything is ok, but on every consecutive show(), I'm getting -10000 from a call me.getXposAlignedToManager() in beforeShow handler.

I was able to getting it work again (at least for my case) with following modification:

beforeShow: function() {
var me = this;
// ...

me.xPosOld = me.xPos;
if (notifications.length) {
me.el.alignTo(notifications[notifications.length - 1].el, me.siblingAlignment, [0, 0]);
me.xPos = me.getXposAlignedToSibling(notifications[notifications.length - 1]);
me.yPos = me.getYposAlignedToSibling(notifications[notifications.length - 1]);
} else {
me.el.alignTo(me.manager.el, me.managerAlignment, [(me.paddingX * me.paddingFactorX), (me.paddingY * me.paddingFactorY)]);
me.xPos = me.getXposAlignedToManager();
me.yPos = me.getYposAlignedToManager();
}

if (me.xPos === -10000) {
me.xPos = me.xPosOld;
}

// ...
}

Does anybody else experience same problems with 4.1.0.RC2? Tnx

Best regards,
Damir Murat

dmurat
6 Apr 2012, 8:56 AM
As it turns out, 4.1.0-rc2 changed visibility mode to 'offsets' for Window class. For restoring correct behavior of Notification, I just set hideMode to 'visibility' in Notification's definition:



Ext.define('Ext.ux.window.Notification', {
extend: 'Ext.window.Window',
alias: 'widget.uxNotification',

hideMode: 'visibility',
cls: 'ux-notification-window',

//...

});


After that, Notification's behavior is restored to normal, as it was before 4.1.0-rc2.

Damir Murat

jiashaoshan@gmail.com
17 Apr 2012, 7:52 PM
do u hava this extension base on Extjs 3.*? i try to rewrite this on 3.* ,bug it looks like difficult

eirik.lorentsen
19 Apr 2012, 7:09 AM
do u hava this extension base on Extjs 3.*? i try to rewrite this on 3.* ,bug it looks like difficult

Yes. Efattal has authored a 3.x Notification extension:
http://www.sencha.com/forum/showthread.php?32365-Ext.ux.Notification
This was the inspiration for the 4.x version.

dcohn
21 May 2012, 6:24 AM
Did you ever figure out how to destroy the notifications after hiding? I'm going to be creating a lot of notifications, I don't want all of the old ones eating up memory once they are hidden.

eirik.lorentsen
21 May 2012, 11:18 AM
Did you ever figure out how to destroy the notifications after hiding? I'm going to be creating a lot of notifications, I don't want all of the old ones eating up memory once they are hidden.

I'll have a look at this as soon as I can find some spare time ;)

hpsam
22 May 2012, 12:17 AM
@dcohn: If I look at the code, the beforehide listener call the destroy. The destroy animate the notification (make it disappear) and then afteranimate call the parent destroy.
So when notification is hidden, it's destroyed.

ldonofrio
22 May 2012, 5:33 AM
I think that you're wrong, look at the dom, markup is still there!
My fix for this, in afteranimate listener add me.destroy at the end:


afteranimate: function () {
if (me.manager) {
var notifications = me.getNotifications(me.managerAlignment);
var index = Ext.Array.indexOf(notifications, me);
if (index != -1) {
Ext.Array.erase(notifications, index, 1);
// Slide "down" all notifications "above" the hidden one
for (;index < notifications.length; index++) {
notifications[index].slideBack();
}
}
}

me.readyToHide = true;
// 2012-05-22 By Ing. Leonardo D'Onofrio (leonardo_donofrio at hotmail.com)
me.destroy();
// end
}



@dcohn: If I look at the code, the beforehide listener call the destroy. The destroy animate the notification (make it disappear) and then afteranimate call the parent destroy.
So when notification is hidden, it's destroyed.

hpsam
22 May 2012, 6:45 AM
I look the code in my app see that I use the version 1.3 of Notification. I haven't seen that a 2.0 version exist.
You're right in the new version the call to destroy is not present.
But they are other changes, and I think the call to destroy must not be in afteranimate but a few lines lower. Like this when animation ended, Ext.Window (parent of Notification) hide() is called, beforehide and hide event are fired and then Notification is destroyed.


me.readyToHide = true;
me.hide();
}
}
});
}

// Calling parents hide function to complete hiding
if (me.readyToHide) {
me.isHiding = false;
me.readyToHide = false;
me.removeCls('notification-fixed');
this.callParent(arguments);
//hpsam: call to destroy after all hide actions are done.
me.destroy();
}

eirik.lorentsen
12 Aug 2012, 7:40 PM
hpsam, dmurat, idonofrio:

I have sorted out the problem with destruction and reuse. The notifications now destroy their dom by default unless closeAction is set to 'hide' in which case the notification never destroys and will allow for repeated update() and show() calls.

I also updated the demo with an example of reuse.

devtig
12 Aug 2012, 11:11 PM
Hi Erik, thanks for your effort. So, I only need to download this to have your improvements?

http://www.eirik.net/Ext/ux/window/Notification.js

eirik.lorentsen
13 Aug 2012, 12:07 PM
That is correct. The new 2.1 version should be backwards compatible with the previous 2.0 version. Just replace the Notification.js file with the one in the link and the changes will take effect.

another_i
17 Aug 2012, 4:03 AM
Great! Thank you!

dunamis
30 Aug 2012, 11:04 PM
Hi, great extension =D>
can I download from somewhere v2.0 I am trying to implement in one ExtJS 4.0.7 project and 2.1 is not working for me.

10x

dmurat
31 Aug 2012, 4:58 PM
Same request as dunamis :-). Please, can you provide dload link for version 2.0. This will be of great help for me, tnx.

caodegao
2 Sep 2012, 5:03 AM
oh! good , i neet this

blagerweij
4 Oct 2012, 11:22 AM
Erik,

What is the license for this extension ? It says in the header that it's dual licensed under MIT and GPL, the GPL is a problem for us, MIT is OK.

Can we use this extension in a commercial application ?

Thanks for the great work,

Barry

eternoendless
12 Oct 2012, 5:23 AM
I too was having troubles making it work on 4.0.7. I've found a copy of version 2.0 after searching a bit, and works great

http://git.php.net/?p=web/doc-editor.git;a=blob_plain;f=extjs/ux/window/Notification.js;h=4cbbc9ca0f96c2cc4176b72010e7cea9899bd772;hb=45ab682ec46c3d75ef

rpieter
15 Oct 2012, 6:59 AM
I wanted to use the plugin to show notifications for reminders.
Turns out that, the moment you create an instance, the popup is shown.
Isn't it possible to create an instance, assign it to a variable, and then call the show()-method using a setTimeout? :-/

I also tried putting the generation of the instance in the setTimeout-function, but that doesn't help, the panel is shown immediately.



var me = this, msTillReminder = 30000, type= 'xxx', queueid=1, recordid=1;
eval('setTimeout(function () {
var rem_' + type + '_' + queueid + '_' + recordid + ' =' + 'Ext.create("Ext.ux.Notification", {' +
'title: "Reminder",' +
'position: "br",' +
'manager: me.id,' +
'stickWhileHover: true,' +
'cls: "ux-notification-light",' +
'iconCls: "ux-notification-icon-reminder",' +
'autoCloseDelay: 6000,' +
'spacing: 20,' +
'slideInDuration: 800,' +
'slideBackDuration: 1500,' +
'slideInAnimation: "bounceOut",' +
'slideBackAnimation: "easeIn",' +
'html: "my text"' +
'}).show() }, ' +
msTillReminder + ')');

rpieter
15 Oct 2012, 11:38 PM
Apparently, this is caused by a browser bug (?).
In my case, the interval used in the setTimeout-function was quite large; 6621707120
I found out that there was a (firefox-)bug posted that calls with a very large timeout would be called prematurely.
So it seems I'll have to limit the time-interval...

eirik.lorentsen
16 Oct 2012, 9:37 AM
blagerweij:
Just pick the license that suits you. Meaning you are completely free to use it in any commercial application under the MIT license.


Erik,

What is the license for this extension ? It says in the header that it's dual licensed under MIT and GPL, the GPL is a problem for us, MIT is OK.

Can we use this extension in a commercial application ?

Thanks for the great work,

Barry

eirik.lorentsen
16 Oct 2012, 9:51 AM
Previous versions can be found here:

2.0:
http://www.eirik.net/Ext/ux/window/tags/Notification/2.0/Notification.js

1.3:
http://www.eirik.net/Ext/ux/window/tags/Notification/1.3/Notification.js

1.2:
http://www.eirik.net/Ext/ux/window/tags/Notification/1.2/Notification.js

1.1:
http://www.eirik.net/Ext/ux/window/tags/Notification/1.1/Notification.js

1.0:
http://www.eirik.net/Ext/ux/window/tags/Notification/1.0/Notification.js

When I find the time I'll try to make a new version compatible with 4.0.7

sebbio
2 Nov 2012, 8:42 AM
How to rearrange the position of the notifications when browser window is resized?

devtig
2 Nov 2012, 8:51 AM
What do you mean with rearrange?

hpsam
5 Nov 2012, 7:13 AM
Hi,

I think it's the same case as sebbio (http://www.sencha.com/forum/member.php?117279-sebbio), but more global.
When the notification manager element size change (floating window resize/move, browser resize...), linked notifications are not moved to match the new element position/size.
In case of browser resize, notifications can be out of screen. If there is a notification with "autoDestroy: false" out of screen, newer positions based on sibling position are all out of screen.

regards

jonathan999
8 Nov 2012, 1:31 AM
I need to use this for my application.
can you please explain how to use it after the notification.js file is downloaded and included in the application.

br,
jonathan

zmengwu
20 Nov 2012, 12:09 AM
I DON'T understand why close the window ,function hide() will be called.


I changed afterShow() as below:


afterShow: function () {
var me = this;


var notifications = me.getNotifications(me.managerAlignment);

if (notifications.length) {
me.el.alignTo(notifications[notifications.length - 1].el, me.siblingAlignment, [0, 0]);
me.xPos = me.getXposAlignedToSibling(notifications[notifications.length - 1]);
me.yPos = me.getYposAlignedToSibling(notifications[notifications.length - 1]);
} else {
me.el.alignTo(me.manager.el, me.managerAlignment, [(me.paddingX * me.paddingFactorX), (me.paddingY * me.paddingFactorY)], false);
me.xPos = me.getXposAlignedToManager();
me.yPos = me.getYposAlignedToManager();
}


Ext.Array.include(notifications, me);


me.el.animate({
to: {
x: me.xPos,
y: me.yPos,
opacity: 1
},
easing: me.slideInAnimation,
duration: me.slideInDuration,
dynamic: true
});


this.callParent(arguments);

var notifications = me.getNotifications(me.managerAlignment);

if(notifications.length > 5){
var closeCount = notifications.length - 5;
for (var i = 0; i < closeCount; i++) {
notifications[i].close();
}
}

},


it exists memory leaking!!!!!!!

zmengwu
20 Nov 2012, 7:17 PM
I t exists memory leaking when keeping on popup windows and being closed Autoly for a long time .

how to improve ?????? Did anybody find it?

devtig
21 Nov 2012, 12:31 AM
I think replacing all instances of me.hide() with me.close() in the code is the way to improve it (I haven't tried it). The default closeAction (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.window.Window-cfg-closeAction) of a window is destroy. So, when you close() a window, the instance is destroyed.

I don't know either why hide is being used.

mikhailt
27 Nov 2012, 4:33 AM
Thank you for your work!
I think this plugin should be adapted as a standard in ExtJS.

lorezyra
2 Dec 2012, 5:53 PM
//I agree, can we push this for consideration at Sencha?
vote++;

eirik.lorentsen
11 Dec 2012, 10:18 AM
I think replacing all instances of me.hide() with me.close() in the code is the way to improve it (I haven't tried it). The default closeAction (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.window.Window-cfg-closeAction) of a window is destroy. So, when you close() a window, the instance is destroyed.

I don't know either why hide is being used.

If I understand it right, then close() is just an alias for hide() or destroy(), depending on what closeAction is set to. In previous versions I always destroyed the Notifications, but in the last version I changed the behavior. The default closeAction of a window is 'destroy', but it can also be set to 'hide' if reusing the window is desirable. The latest changes I made make it possible to reuse a notification object the same way.

For example if you check out the latest demo (http://www.eirik.net/Ext/ux/window/Notification.html) there is a button that says "BR - reuse". This shows the reuse of the component and the dom. A nice side effect in the example is that this automatically restricts the number of notifications to only one.

And the script actually does not call hide() more than once. From inside the overridden destroy() function. The reason for this is to make sure the notification fades out with an animation not only when the script closes it after the delay (autoClose), but also when the close button in the top right hand corner is clicked. There might be a way of achieving this without touching the destroy() function, but I felt it made sense to always hide the notification with the animation before it is destroyed.

After the hide animation is finished a new call is made to destroy() and the second time around a call is made to me.callParent(arguments) inside destroy(). So I am under the impression that this means all other destruction that windows normally perform will take place. The dom certainly is destroyed and I figured that was mostly what the destroy() functions did in Ext (take down the related dom). If there is a memory leak caused by the overriding of the destroy() function, then maybe that is because something else, like a pointer or circualar reference, should also be destroyed before exiting the overridden destroy() function. But since hide() calls removeFromManager(), then I can't imagine where those pointers are.

When it comes to memory management I'm on thin ice. Both JS and Ext wise. So maybe somebody could help out with some more insight? Or simply tell me a procedure I could use to test/visualize the leak, providing me a way to debug it.

eirik.lorentsen
11 Dec 2012, 10:21 AM
//I agree, can we push this for consideration at Sencha?
vote++;

Great idea. I wouldn't mind at all!

eirik.lorentsen
11 Dec 2012, 10:22 AM
I need to use this for my application.
can you please explain how to use it after the notification.js file is downloaded and included in the application.

br,
jonathan

View the source from the demo page:
http://www.eirik.net/Ext/ux/window/Notification.html

mjhaston
31 Jan 2013, 10:43 AM
Great extension. I apologize if this was noted already, but how do I make a notification stick until it's manually closed or I close it programatically?

Thanks.

eirik.lorentsen
31 Jan 2013, 12:12 PM
Pass the following parameter to the constructor and the notification will not go anywhere:
autoClose: false



Great extension. I apologize if this was noted already, but how do I make a notification stick until it's manually closed or I close it programatically?

Thanks.

silcreval
16 Feb 2013, 3:39 AM
Is there a way to either reuse or prevent multiple notifications appearing (that are the same)?

eirik.lorentsen
18 Feb 2013, 5:50 AM
Is there a way to either reuse or prevent multiple notifications appearing (that are the same)?

Yes. In the demo there is a button called "BR - reuse" demonstrating exactly how to do this.

In short you store the pointer to the notification when you create it. This can be done in advance as long as you don't call the show() immediately. And then you only call update/show every time you want to notify something. If the notification is still visible when the next updtae/show is called then all that happens is an update of the notification's content.

Refus
10 Apr 2013, 11:45 PM
in 4.2 fails to destroy the component.
so it works again:


hide: function () {
var me = this;
// Avoids restarting the last animation on an element already underway with its hide animation
if (!me.isHiding && me.el) {


me.isHiding = true;


me.cancelAutoClose();
me.stopAnimation();


me.el.animate({
to: {
opacity: 0
},
easing: 'easeIn',
duration: me.hideDuration,
dynamic: false,
listeners: {
afteranimate: function () {
me.removeFromManager();
me.readyToHide = true;
if(!me.destroying){
me.hide(me.animateTarget, me.doClose, me);}
}
}
});
}
...

wemerson.januario
19 Apr 2013, 1:57 PM
Animation fails in ExtJS 4.2.1 beta 1

bseddon
14 Jun 2013, 3:24 AM
Hi Eirik

I've run into a problem using the notification window. I want to share my workaround in case it's useful for others.

The content of my popup window is a label control and a grid arranged in a vbox layout. I want the window to size dynamically to the content and I want the window to emerge from the bottom. The problem I've had is that the notification window computes the offsets required for the animation in 'afterShow'.

If the window layout is the default 'auto' this is fine because the correct window height has been computed by the time the window is show. However, if the content is dependent upon the layout engine then by the time afterShow is called, the height will be whatever initial minimal height ExtJS uses (zero or minHeight for example).

My solution is to move the code in 'afterShow' to new function 'doAnimation' which is called from 'afterLayout'. Now this is not the whole story in a couple of ways.

One is that 'afterLayout' is fired repeatedly but only once after 'afterShow' So the trick is to record the show event in 'afterShow' and arrange that the code in 'afterLayout' executes only once after the window has been shown (see the code snippet below).

The other issue is that 'afterLayout' is only called if a layout is used. By default the notification window does not use a layout so the 'auto' layout is used. In this case 'autoLayout' is not called after 'afterShow'. If the only place 'doAnimation' is called is in 'afterLayout' then the window will never appear. This means 'doAnimiation' should be called from 'afterShow' if this.getLayout().$className == 'Ext.layout.container.Auto' or from 'afterLayout' otherwise.

The only other wrinkle is that when doAnimation is called from afterLayout, the windows does not seem to be active. To address that I've added a call to setActive();

This change works for me in the narrow case of my scenario and is not tested to work in all scenarios. However, the relevant code change in my implementation of the notification window can be shown like this:



afterShow: function () {

if (this.getLayout().$className === 'Ext.layout.container.Auto')
this.doAnimation();
else
this.shown = true;

this.callParent(arguments);
},


afterLayout: function() {

var me = this;
if (!me.shown) return;
delete this.shown;

this.callParent(arguments);

me.setActive(true);
me.doAnimation();
},

doAnimation: function() {
// The rest of the 'afterShow' code appears here...
}

paulosincos
2 Jul 2013, 6:59 AM
Nice feature! thanks

rafaelrp
3 Jul 2013, 9:23 AM
Nice!

Scorpie
4 Jul 2013, 1:04 AM
Is this compatible with the neptune theme? I tried it but it doesnt look 'smooth'.

nbabinski
10 Jul 2013, 2:07 AM
Hello Eirik,
Thanks for the great extension!

One proposal to share the code of this great ux in any social coding places like github, making future developing easier and of course collaboration with the community.
I've found that you've joined the github (https://github.com/EirikLorentsen) will be great to move development there.

brian428
25 Aug 2013, 10:31 AM
Erik, great work on this. But I thought I'd ask about an issue that seems to have popped up in 4.2.1. When a Notification is rendered, it starts off in the top right (if I've set it to TR of course), but then jumps to the center of the screen, and then animates from screen center back up to the top right. I assume something changed in 4.2.1 either in the CSS or maybe in how relative X/Y are calculated or something. Before I dive in over my head to try and see if I can figure it out, I figured I'd ask if you've seen this or had any ideas. Was hoping maybe it's something you'd be able to identify quickly since you're so familiar with the code. If not, I plan to try and dig in and see if I can figure out what's changed.

Thanks,

Brian

brian428
25 Aug 2013, 11:43 AM
I think I found it. For some reason, it looks like the actual x and y isn't being set initially on the window (and probably its underlying El?). I force these to be set in the beforeShow() handler, just before the call to me.el.animate() by adding this:

me.x = me.getX();
me.y = me.getY();

Seems to work correctly on 4.2.1 now!

eirik.lorentsen
30 Aug 2013, 4:42 PM
Good point!
The plugin is now a project on GitHub:
https://github.com/EirikLorentsen/Ext.ux.window.Notification

adolfo9
3 Sep 2013, 10:33 AM
i have problems with version ExtJs. v.4.2.1 ..the window notification show on top, but no show the window complete, only one section of window.... when i use extjs v .4.1 work fine... but with version. 4.2.1 not work.... one suggestion for fix the problem?

eirik.lorentsen
3 Sep 2013, 2:33 PM
Scorpie: There should be no problem using themes. The basic plugin does not modify any markup. The notifications are identical to windows in that respect.
However my alternative styling in the demo might look a bit off because it is modifying the css of the base theme. But if you are using the Neptune theme you probably don't want to use the alternative styling anyway..

eirik.lorentsen
3 Sep 2013, 2:34 PM
brian428: I can't seem to replicate this behaviour in my demo using the 4.2.1 cdn. Could you post some code or a link so I can test this?

eirik.lorentsen
3 Sep 2013, 2:44 PM
New version released.
This one compatible with Ext JS 4.0.7 and with a much simplified hide() override using fadeOut() and eliminating various small snags.

eirik.lorentsen
3 Sep 2013, 2:46 PM
i have problems with version ExtJs. v.4.2.1 ..the window notification show on top, but no show the window complete, only one section of window.... when i use extjs v .4.1 work fine... but with version. 4.2.1 not work.... one suggestion for fix the problem?

I can't easily reproduce this error. Could you post a link to a jsfiddle demonstrating the bug?

adolfo9
6 Sep 2013, 6:12 AM
Hi
Testing only ux.window.Notification isolated, and work fine.... the problem must be something else... thanks for the extension and sorry for the false alarm

jlamberink
12 Sep 2013, 5:15 AM
I think I found it. For some reason, it looks like the actual x and y isn't being set initially on the window (and probably its underlying El?). I force these to be set in the beforeShow() handler, just before the call to me.el.animate() by adding this:

me.x = me.getX();
me.y = me.getY();

Seems to work correctly on 4.2.1 now!
You're a lifesaver! I couldn't figure out what was going wrong, just that the start position for the animation was wrong somehow. I had kind of given up when I found this thread, and your addition to the beforeShow() handler works perfectly!

jlamberink
13 Sep 2013, 1:26 AM
I have a bug when there are multiple notifications, they don't align neatly, but their (x,y) position decreases gradually. After a lot of bug fixing, I've found that this is due to the getWidth() and getHeight() methods not returning the correct value during the beforeShow() method.

I am using Ext JS 4.2 and version 2.0 of this plugin/extension.

eirik.lorentsen
13 Sep 2013, 7:54 AM
I have a bug when there are multiple notifications, they don't align neatly, but their (x,y) position decreases gradually. After a lot of bug fixing, I've found that this is due to the getWidth() and getHeight() methods not returning the correct value during the beforeShow() method.

I am using Ext JS 4.2 and version 2.0 of this plugin/extension.

Have you tried upgrading to the newest version of the plugin (2.1.2)?
It should work fine with Ext JS 4.2.x and any other version of Ext JS from 4.0.2 and up.

jlamberink
16 Sep 2013, 12:47 AM
Updating did the trick! It also solved another minor issue with the notifications appearing behind a mask. Thanks for the advice :D

felix41382
3 Dec 2013, 11:48 PM
Thanks for this great extension!

Cheers,
Felix

talha06
6 Jan 2014, 7:14 AM
it is working very well with the latest version of Ext JS(4.2.1). Thanks a lot Eirick!

javapurna
2 Feb 2014, 9:34 PM
Hi eirik.lorentsen,

how to show list of notifications .for suppose 10 notifications coming from database at once (Array[10])

i am create like below



for(var i=0;i<event.data.length;i++){
var notification =Ext.create("MotApp.util.Notification", {
title: 'Notification',
position: "br",// Options: br, bl, tr, tl, t, l, b, r
cls: "ux-notification-window ux-notification-success",
iconCls: "ux-notification-icon-information",
spacing: 15,
html:event.data[i].message,
autoCloseDelay: 7000,
});
notification.show(); }


event.data contains Array[10] objects . i am iterating and displaying . but all notifications close at a time.




)

brian428
2 Feb 2014, 9:52 PM
If you set them all to close after 7000 ms, then that's when they'll all close.

Also, showing 10 simultaneous notifications is a really poor UX choice. Either reduce the noise, or combine them into one notification.

JK3jp5qMJwKW
3 Mar 2014, 6:13 PM
He released a new version: 2.1.3http://www.eirik.net/Ext/ux/window/Notification.js