source: Dev/trunk/src/client/dojox/widget/Toaster.js @ 485

Last change on this file since 485 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 9.1 KB
Line 
1define([
2        "dojo/_base/declare", // declare
3        "dojo/_base/lang", // lang.getObject...
4        "dojo/_base/connect", // connect.connect, connect.subscribe
5        "dojo/_base/fx", // fx.fadeOut
6        "dojo/dom-style", // domStyle.set
7        "dojo/dom-class", // domClass.add
8        "dojo/dom-geometry", // domGeometry.getMarginBox
9        "dijit/registry",    // registry.getUniqueId()
10        "dijit/_WidgetBase",
11        "dijit/_TemplatedMixin",
12        "dijit/BackgroundIframe",
13        "dojo/fx",
14        "dojo/has",
15        "dojo/_base/window",
16        "dojo/window"
17], function(declare, lang, connect, baseFx, domStyle, domClass, domGeometry, registry, WidgetBase, Templated, BackgroundIframe, coreFx, has, baseWindow, window){
18
19        lang.getObject("dojox.widget", true);
20       
21        var capitalize = function(/* String */w){
22            return w.substring(0,1).toUpperCase() + w.substring(1);
23        };
24
25        return declare("dojox.widget.Toaster", [WidgetBase, Templated], {
26                // summary:
27                //              Message that slides in from the corner of the screen, used for notifications
28                //              like "new email".
29
30                templateString: '<div class="dijitToasterClip" dojoAttachPoint="clipNode"><div class="dijitToasterContainer" dojoAttachPoint="containerNode" dojoAttachEvent="onclick:onSelect"><div class="dijitToasterContent" dojoAttachPoint="contentNode"></div></div></div>',
31
32                // messageTopic: String
33                //              Name of topic; anything published to this topic will be displayed as a message.
34                //              Message format is either String or an object like
35                //              {message: "hello word", type: "error", duration: 500}
36                messageTopic: "",
37
38                // messageTypes: Enumeration
39                //              Possible message types.
40                messageTypes: {
41                        MESSAGE: "message",
42                        WARNING: "warning",
43                        ERROR: "error",
44                        FATAL: "fatal"
45                },
46
47                // defaultType: String
48                //              If message type isn't specified (see "messageTopic" parameter),
49                //              then display message as this type.
50                //              Possible values in messageTypes enumeration ("message", "warning", "error", "fatal")
51                defaultType: "message",
52
53                // positionDirection: String
54                //              Position from which message slides into screen, one of
55                //              ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"]
56                positionDirection: "br-up",
57
58                // positionDirectionTypes: Array
59                //              Possible values for positionDirection parameter
60                positionDirectionTypes: ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"],
61
62                // duration: Integer
63                //              Number of milliseconds to show message
64                duration: 2000,
65
66                // slideDuration: Integer
67                //              Number of milliseconds for the slide animation, increasing will cause the Toaster
68                //              to slide in more slowly.
69                slideDuration: 500,
70
71                // separator: String
72                //              String used to separate messages if consecutive calls are made to setContent before previous messages go away
73                separator: "<hr></hr>",
74
75                postCreate: function(){
76                        this.inherited(arguments);
77                        this.hide();
78
79                        // place node as a child of body for positioning
80                        baseWindow.body().appendChild(this.domNode);
81
82                        if(this.messageTopic){
83                                connect.subscribe(this.messageTopic, this, "_handleMessage");
84                        }
85                },
86
87                _handleMessage: function(/*String|Object*/message){
88                        if(lang.isString(message)){
89                                this.setContent(message);
90                        }else{
91                                this.setContent(message.message, message.type, message.duration);
92                        }
93                },
94
95                setContent: function(/*String|Function*/message, /*String*/messageType, /*int?*/duration){
96                        // summary:
97                        //              sets and displays the given message and show duration
98                        // message:
99                        //              the message. If this is a function, it will be called with this toaster widget as the only argument.
100                        // messageType:
101                        //              type of message; possible values in messageTypes enumeration ("message", "warning", "error", "fatal")
102                        // duration:
103                        //              duration in milliseconds to display message before removing it. Widget has default value.
104                        duration = duration||this.duration;
105                        // sync animations so there are no ghosted fades and such
106                        if(this.slideAnim){
107                                if(this.slideAnim.status() != "playing"){
108                                        this.slideAnim.stop();
109                                }
110                                if(this.slideAnim.status() == "playing" || (this.fadeAnim && this.fadeAnim.status() == "playing")){
111                                        setTimeout(lang.hitch(this, function(){
112                                                this.setContent(message, messageType, duration);
113                                        }), 50);
114                                        return;
115                                }
116                        }
117
118                        // determine type of content and apply appropriately
119                        for(var type in this.messageTypes){
120                                domClass.remove(this.containerNode, "dijitToaster" + capitalize(this.messageTypes[type]));
121                        }
122
123                        domStyle.set(this.containerNode, "opacity", 1);
124
125                        this._setContent(message);
126
127                        domClass.add(this.containerNode, "dijitToaster" + capitalize(messageType || this.defaultType));
128
129                        // now do funky animation of widget appearing from
130                        // bottom right of page and up
131                        this.show();
132                        var nodeSize = domGeometry.getMarginBox(this.containerNode);
133                        this._cancelHideTimer();
134                        if(this.isVisible){
135                                this._placeClip();
136                                //update hide timer if no sticky message in stack
137                                if(!this._stickyMessage) {
138                                        this._setHideTimer(duration);
139                                }
140                        }else{
141                                var style = this.containerNode.style;
142                                var pd = this.positionDirection;
143                                // sets up initial position of container node and slide-out direction
144                                if(pd.indexOf("-up") >= 0){
145                                        style.left=0+"px";
146                                        style.top=nodeSize.h + 10 + "px";
147                                }else if(pd.indexOf("-left") >= 0){
148                                        style.left=nodeSize.w + 10 +"px";
149                                        style.top=0+"px";
150                                }else if(pd.indexOf("-right") >= 0){
151                                        style.left = 0 - nodeSize.w - 10 + "px";
152                                        style.top = 0+"px";
153                                }else if(pd.indexOf("-down") >= 0){
154                                        style.left = 0+"px";
155                                        style.top = 0 - nodeSize.h - 10 + "px";
156                                }else{
157                                        throw new Error(this.id + ".positionDirection is invalid: " + pd);
158                                }
159                                this.slideAnim = coreFx.slideTo({
160                                        node: this.containerNode,
161                                        top: 0, left: 0,
162                                        duration: this.slideDuration});
163                                this.connect(this.slideAnim, "onEnd", function(nodes, anim){
164                                                //we build the fadeAnim here so we dont have to duplicate it later
165                                                // can't do a fadeHide because we're fading the
166                                                // inner node rather than the clipping node
167                                                this.fadeAnim = baseFx.fadeOut({
168                                                        node: this.containerNode,
169                                                        duration: 1000});
170                                                this.connect(this.fadeAnim, "onEnd", function(evt){
171                                                        this.isVisible = false;
172                                                        this.hide();
173                                                });
174                                                this._setHideTimer(duration);
175                                                this.connect(this, 'onSelect', function(evt){
176                                                        this._cancelHideTimer();
177                                                        //force clear sticky message
178                                                        this._stickyMessage=false;
179                                                        this.fadeAnim.play();
180                                                });
181
182                                                this.isVisible = true;
183                                        });
184                                this.slideAnim.play();
185                        }
186                },
187
188                _setContent: function(message){
189                        if(lang.isFunction(message)){
190                                message(this);
191                                return;
192                        }
193                        if(message && this.isVisible){
194                                message = this.contentNode.innerHTML + this.separator + message;
195                        }
196                        this.contentNode.innerHTML = message;
197                },
198                _cancelHideTimer:function(){
199                        if (this._hideTimer){
200                                clearTimeout(this._hideTimer);
201                                this._hideTimer=null;
202                        }
203                },
204
205                _setHideTimer:function(duration){
206                        this._cancelHideTimer();
207                        //if duration == 0 we keep the message displayed until clicked
208                        if(duration>0){
209                                this._cancelHideTimer();
210                                this._hideTimer=setTimeout(lang.hitch(this, function(evt){
211                                        // we must hide the iframe in order to fade
212                                        // TODO: figure out how to fade with a BackgroundIframe
213                                        if(this.bgIframe && this.bgIframe.iframe){
214                                                this.bgIframe.iframe.style.display="none";
215                                        }
216                                        this._hideTimer=null;
217                                        //force clear sticky message
218                                        this._stickyMessage=false;
219                                        this.fadeAnim.play();
220                                }), duration);
221                        }
222                        else
223                                this._stickyMessage=true;
224                },
225
226                _placeClip: function(){
227                        var view = window.getBox();
228
229                        var nodeSize = domGeometry.getMarginBox(this.containerNode);
230
231                        var style = this.clipNode.style;
232                        // sets up the size of the clipping node
233                        style.height = nodeSize.h+"px";
234                        style.width = nodeSize.w+"px";
235
236                        // sets up the position of the clipping node
237                        var pd = this.positionDirection;
238                        if(pd.match(/^t/)){
239                                style.top = view.t+"px";
240                        }else if(pd.match(/^b/)){
241                                style.top = (view.h - nodeSize.h - 2 + view.t)+"px";
242                        }
243                        if(pd.match(/^[tb]r-/)){
244                                style.left = (view.w - nodeSize.w - 1 - view.l)+"px";
245                        }else if(pd.match(/^[tb]l-/)){
246                                style.left = 0 + "px";
247                        }else if(pd.match(/^[tb]c-/)){
248                                style.left = Math.round((view.w - nodeSize.w - 1 - view.l)/2)+"px";
249                        }
250
251                        style.clip = "rect(0px, " + nodeSize.w + "px, " + nodeSize.h + "px, 0px)";
252                        if(has("ie")){
253                                if(!this.bgIframe){
254                                        this.clipNode.id = registry.getUniqueId("dojox_widget_Toaster_clipNode");
255                                        this.bgIframe = new BackgroundIframe(this.clipNode);
256                                }
257                                var iframe = this.bgIframe.iframe;
258                                if(iframe){ iframe.style.display="block"; }
259                        }
260                },
261
262                onSelect: function(/*Event*/e){
263                        // summary:
264                        //              callback for when user clicks the message
265                },
266
267                show: function(){
268                        // summary:'
269                        //              show the Toaster
270                        domStyle.set(this.domNode, 'display', 'block');
271
272                        this._placeClip();
273
274                        if(!this._scrollConnected){
275                                this._scrollConnected = connect.connect(window, "onscroll", this, this._placeClip);
276                        }
277                },
278
279                hide: function(){
280                        // summary:
281                        //              hide the Toaster
282
283                        domStyle.set(this.domNode, 'display', 'none');
284
285                        if(this._scrollConnected){
286                                connect.disconnect(this._scrollConnected);
287                                this._scrollConnected = false;
288                        }
289
290                        domStyle.set(this.containerNode, "opacity", 1);
291                }
292        });
293
294});
Note: See TracBrowser for help on using the repository browser.