123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- define("dojox/widget/Toaster", [
- "dojo/_base/declare", // declare
- "dojo/_base/lang", // lang.getObject...
- "dojo/_base/connect", // connect.connect, connect.subscribe
- "dojo/_base/fx", // fx.fadeOut
- "dojo/dom-style", // domStyle.set
- "dojo/dom-class", // domClass.add
- "dojo/dom-geometry", // domGeometry.getMarginBox
- "dijit/registry", // registry.getUniqueId()
- "dijit/_WidgetBase",
- "dijit/_TemplatedMixin",
- "dijit/BackgroundIframe",
- "dojo/fx",
- "dojo/has",
- "dojo/_base/window",
- "dojo/window"
- ], function(declare, lang, connect, baseFx, domStyle, domClass, domGeometry, registry, WidgetBase, Templated, BackgroundIframe, coreFx, has, baseWindow, window){
- lang.getObject("dojox.widget", true);
- var capitalize = function(/* String */w){
- return w.substring(0,1).toUpperCase() + w.substring(1);
- };
- return declare("dojox.widget.Toaster", [WidgetBase, Templated], {
- // summary:
- // Message that slides in from the corner of the screen, used for notifications
- // like "new email".
- templateString: '<div class="dijitToasterClip" dojoAttachPoint="clipNode"><div class="dijitToasterContainer" dojoAttachPoint="containerNode" dojoAttachEvent="onclick:onSelect"><div class="dijitToasterContent" dojoAttachPoint="contentNode"></div></div></div>',
- // messageTopic: String
- // Name of topic; anything published to this topic will be displayed as a message.
- // Message format is either String or an object like
- // {message: "hello word", type: "error", duration: 500}
- messageTopic: "",
- // messageTypes: Enumeration
- // Possible message types.
- messageTypes: {
- MESSAGE: "message",
- WARNING: "warning",
- ERROR: "error",
- FATAL: "fatal"
- },
- // defaultType: String
- // If message type isn't specified (see "messageTopic" parameter),
- // then display message as this type.
- // Possible values in messageTypes enumeration ("message", "warning", "error", "fatal")
- defaultType: "message",
- // positionDirection: String
- // Position from which message slides into screen, one of
- // ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"]
- positionDirection: "br-up",
- // positionDirectionTypes: Array
- // Possible values for positionDirection parameter
- positionDirectionTypes: ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"],
- // duration: Integer
- // Number of milliseconds to show message
- duration: 2000,
- // slideDuration: Integer
- // Number of milliseconds for the slide animation, increasing will cause the Toaster
- // to slide in more slowly.
- slideDuration: 500,
- //separator: String
- // String used to separate messages if consecutive calls are made to setContent before previous messages go away
- separator: "<hr></hr>",
- postCreate: function(){
- this.inherited(arguments);
- this.hide();
- // place node as a child of body for positioning
- baseWindow.body().appendChild(this.domNode);
- if(this.messageTopic){
- connect.subscribe(this.messageTopic, this, "_handleMessage");
- }
- },
- _handleMessage: function(/*String|Object*/message){
- if(lang.isString(message)){
- this.setContent(message);
- }else{
- this.setContent(message.message, message.type, message.duration);
- }
- },
- setContent: function(/*String|Function*/message, /*String*/messageType, /*int?*/duration){
- // summary:
- // sets and displays the given message and show duration
- // message:
- // the message. If this is a function, it will be called with this toaster widget as the only argument.
- // messageType:
- // type of message; possible values in messageTypes enumeration ("message", "warning", "error", "fatal")
- // duration:
- // duration in milliseconds to display message before removing it. Widget has default value.
- duration = duration||this.duration;
- // sync animations so there are no ghosted fades and such
- if(this.slideAnim){
- if(this.slideAnim.status() != "playing"){
- this.slideAnim.stop();
- }
- if(this.slideAnim.status() == "playing" || (this.fadeAnim && this.fadeAnim.status() == "playing")){
- setTimeout(lang.hitch(this, function(){
- this.setContent(message, messageType, duration);
- }), 50);
- return;
- }
- }
- // determine type of content and apply appropriately
- for(var type in this.messageTypes){
- domClass.remove(this.containerNode, "dijitToaster" + capitalize(this.messageTypes[type]));
- }
- domStyle.set(this.containerNode, "opacity", 1);
- this._setContent(message);
- domClass.add(this.containerNode, "dijitToaster" + capitalize(messageType || this.defaultType));
- // now do funky animation of widget appearing from
- // bottom right of page and up
- this.show();
- var nodeSize = domGeometry.getMarginBox(this.containerNode);
- this._cancelHideTimer();
- if(this.isVisible){
- this._placeClip();
- //update hide timer if no sticky message in stack
- if(!this._stickyMessage) {
- this._setHideTimer(duration);
- }
- }else{
- var style = this.containerNode.style;
- var pd = this.positionDirection;
- // sets up initial position of container node and slide-out direction
- if(pd.indexOf("-up") >= 0){
- style.left=0+"px";
- style.top=nodeSize.h + 10 + "px";
- }else if(pd.indexOf("-left") >= 0){
- style.left=nodeSize.w + 10 +"px";
- style.top=0+"px";
- }else if(pd.indexOf("-right") >= 0){
- style.left = 0 - nodeSize.w - 10 + "px";
- style.top = 0+"px";
- }else if(pd.indexOf("-down") >= 0){
- style.left = 0+"px";
- style.top = 0 - nodeSize.h - 10 + "px";
- }else{
- throw new Error(this.id + ".positionDirection is invalid: " + pd);
- }
- this.slideAnim = coreFx.slideTo({
- node: this.containerNode,
- top: 0, left: 0,
- duration: this.slideDuration});
- this.connect(this.slideAnim, "onEnd", function(nodes, anim){
- //we build the fadeAnim here so we dont have to duplicate it later
- // can't do a fadeHide because we're fading the
- // inner node rather than the clipping node
- this.fadeAnim = baseFx.fadeOut({
- node: this.containerNode,
- duration: 1000});
- this.connect(this.fadeAnim, "onEnd", function(evt){
- this.isVisible = false;
- this.hide();
- });
- this._setHideTimer(duration);
- this.connect(this, 'onSelect', function(evt){
- this._cancelHideTimer();
- //force clear sticky message
- this._stickyMessage=false;
- this.fadeAnim.play();
- });
- this.isVisible = true;
- });
- this.slideAnim.play();
- }
- },
- _setContent: function(message){
- if(lang.isFunction(message)){
- message(this);
- return;
- }
- if(message && this.isVisible){
- message = this.contentNode.innerHTML + this.separator + message;
- }
- this.contentNode.innerHTML = message;
- },
- _cancelHideTimer:function(){
- if (this._hideTimer){
- clearTimeout(this._hideTimer);
- this._hideTimer=null;
- }
- },
- _setHideTimer:function(duration){
- this._cancelHideTimer();
- //if duration == 0 we keep the message displayed until clicked
- if(duration>0){
- this._cancelHideTimer();
- this._hideTimer=setTimeout(lang.hitch(this, function(evt){
- // we must hide the iframe in order to fade
- // TODO: figure out how to fade with a BackgroundIframe
- if(this.bgIframe && this.bgIframe.iframe){
- this.bgIframe.iframe.style.display="none";
- }
- this._hideTimer=null;
- //force clear sticky message
- this._stickyMessage=false;
- this.fadeAnim.play();
- }), duration);
- }
- else
- this._stickyMessage=true;
- },
- _placeClip: function(){
- var view = window.getBox();
- var nodeSize = domGeometry.getMarginBox(this.containerNode);
- var style = this.clipNode.style;
- // sets up the size of the clipping node
- style.height = nodeSize.h+"px";
- style.width = nodeSize.w+"px";
- // sets up the position of the clipping node
- var pd = this.positionDirection;
- if(pd.match(/^t/)){
- style.top = view.t+"px";
- }else if(pd.match(/^b/)){
- style.top = (view.h - nodeSize.h - 2 + view.t)+"px";
- }
- if(pd.match(/^[tb]r-/)){
- style.left = (view.w - nodeSize.w - 1 - view.l)+"px";
- }else if(pd.match(/^[tb]l-/)){
- style.left = 0 + "px";
- }
- style.clip = "rect(0px, " + nodeSize.w + "px, " + nodeSize.h + "px, 0px)";
- if(has("ie")){
- if(!this.bgIframe){
- if (!this.clipNode.id) {
- this.clipNode.id = registry.getUniqueId("dojox_widget_Toaster_clipNode");
- }
- this.bgIframe = new BackgroundIframe(this.clipNode);
- }
- var iframe = this.bgIframe.iframe;
- if(iframe){ iframe.style.display="block"; }
- }
- },
- onSelect: function(/*Event*/e){
- // summary: callback for when user clicks the message
- },
- show: function(){
- // summary: show the Toaster
- domStyle.set(this.domNode, 'display', 'block');
- this._placeClip();
- if(!this._scrollConnected){
- this._scrollConnected = connect.connect(window, "onscroll", this, this._placeClip);
- }
- },
- hide: function(){
- // summary: hide the Toaster
- domStyle.set(this.domNode, 'display', 'none');
- if(this._scrollConnected){
- connect.disconnect(this._scrollConnected);
- this._scrollConnected = false;
- }
- domStyle.set(this.containerNode, "opacity", 1);
- }
- });
- });
|