Select to view content in your preferred language

dojox toaster in map div

1788
3
Jump to solution
10-03-2013 01:45 PM
JeffreySchmidt
Deactivated User
I was interested in using the Dojox widget toaster.  I am able to get it to show up, but cannot seem to place it in the center map div.

A google search notes that others were interested as well...
http://dojo-toolkit.33424.n3.nabble.com/attaching-dojox-widget-Toaster-to-center-pane-in-BorderConta...

Anyone got any ideas on how to place a toaster into the center map container???

using the chrome console I attempted to place the toaster but with no luck.... dojo.place('mytoaster', 'mapdiv')

As a work-around, I could use a dialog or simply populate, show and then fade out a div in the map div, but I'd like to use toaster if I can... 🙂
0 Kudos
1 Solution

Accepted Solutions
BenFousek
Deactivated User
I GUESS THERE'S A CHARACTER LIMIT SO THIS IS COMING IN TWO PARTS...

It's the default nature of the toaster is to have the window as it's container. It's a modification to the widget time! Here's my modification to 1) set the target to the map (or any other element with an id) and 2) add center down. I started to add center up but never did. The the other positions may or may not work. As I recall there was an issue with right. All I wanted was center down so I didn't go any further or clean it up (probably buried 42 pages deep in my to do list).

Notes:
The namespace and class are changed to mods.widget.MapToaster. Change to your custom module path. Of course all dojo module naming and path conventions must be followed.

Anything I changed is proceeded with //MODIFY and a brief description of the change.

This is uncompressed and still contains the author's comments.

The widget code:
define([   "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);   };   //MODIFY dojox.widget.Toaster to mods.widget.MapToaster   return declare("mods.widget.MapToaster", [WidgetBase, Templated], {     // summary:     //  Message that slides in from the corner of the screen, used for notifications     //  like "new email".     //MODIFY add "Map" to classes     templateString: '<div class="dijitMapToasterClip" dojoAttachPoint="clipNode"><div class="dijitMapToasterContainer" dojoAttachPoint="containerNode" dojoAttachEvent="onclick:onSelect"><div class="dijitMapToasterContent" 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"]     //MODIFY default to "tc-down"     positionDirection: "tc-down",      // positionDirectionTypes: Array     //  Possible values for positionDirection parameter     //MODIFY add direction types "bc-up" and "tc-down"     positionDirectionTypes: ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right", "bc-up", "tc-down"],      // 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     //MODIFY no need for separator - see _setContent     //separator: "<hr></hr>",      //MODIFY map div (or other container) id     mapId: 'map',      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) {         //MODIFY add "Map" to classes         domClass.remove(this.containerNode, "dijitMapToaster" + capitalize(this.messageTypes[type]));       }        domStyle.set(this.containerNode, "opacity", 1);        this._setContent(message);        //MODIFY add "Map" to classes       domClass.add(this.containerNode, "dijitMapToaster" + 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();       }     }, //CONTINUED IN NEXT POST

View solution in original post

0 Kudos
3 Replies
BenFousek
Deactivated User
I GUESS THERE'S A CHARACTER LIMIT SO THIS IS COMING IN TWO PARTS...

It's the default nature of the toaster is to have the window as it's container. It's a modification to the widget time! Here's my modification to 1) set the target to the map (or any other element with an id) and 2) add center down. I started to add center up but never did. The the other positions may or may not work. As I recall there was an issue with right. All I wanted was center down so I didn't go any further or clean it up (probably buried 42 pages deep in my to do list).

Notes:
The namespace and class are changed to mods.widget.MapToaster. Change to your custom module path. Of course all dojo module naming and path conventions must be followed.

Anything I changed is proceeded with //MODIFY and a brief description of the change.

This is uncompressed and still contains the author's comments.

The widget code:
define([   "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);   };   //MODIFY dojox.widget.Toaster to mods.widget.MapToaster   return declare("mods.widget.MapToaster", [WidgetBase, Templated], {     // summary:     //  Message that slides in from the corner of the screen, used for notifications     //  like "new email".     //MODIFY add "Map" to classes     templateString: '<div class="dijitMapToasterClip" dojoAttachPoint="clipNode"><div class="dijitMapToasterContainer" dojoAttachPoint="containerNode" dojoAttachEvent="onclick:onSelect"><div class="dijitMapToasterContent" 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"]     //MODIFY default to "tc-down"     positionDirection: "tc-down",      // positionDirectionTypes: Array     //  Possible values for positionDirection parameter     //MODIFY add direction types "bc-up" and "tc-down"     positionDirectionTypes: ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right", "bc-up", "tc-down"],      // 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     //MODIFY no need for separator - see _setContent     //separator: "<hr></hr>",      //MODIFY map div (or other container) id     mapId: 'map',      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) {         //MODIFY add "Map" to classes         domClass.remove(this.containerNode, "dijitMapToaster" + capitalize(this.messageTypes[type]));       }        domStyle.set(this.containerNode, "opacity", 1);        this._setContent(message);        //MODIFY add "Map" to classes       domClass.add(this.containerNode, "dijitMapToaster" + 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();       }     }, //CONTINUED IN NEXT POST
0 Kudos
BenFousek
Deactivated User
//CONTINUED FROM LAST POST
    _setContent: function (message) {
      if (lang.isFunction(message)) {
        message(this);
        return;
      }
      //MODIFY if the toaster is visible simply switch out the current message with new message
      /*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 () {
      //MODIFY view is the map (or other container) and border is its border
      //var view = window.getBox();
      var pos = domGeometry.position(this.mapId);
      var view = {
        w: pos.w,
        h: pos.h,
        t: pos.y,
        l: pos.x
      };

      var border = domGeometry.getBorderExtents(this.mapId);

      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/)) {
        //MODIFY + border top
        //style.top = view.t+"px";
        style.top = (view.t + border.t) + "px";
      } else if (pd.match(/^b/)) {
        //MODIFY + border top
        //style.top = (view.h - nodeSize.h - 2 + view.t)+"px";
        style.top = (view.h - nodeSize.h - 2 + view.t + border.t) + "px";
      }
      if (pd.match(/^[tb]r-/)) {
        style.left = (view.w - nodeSize.w - 1 - view.l) + "px";
      } else if (pd.match(/^[tb]l-/)) {
        //MODIFY [top/bottom]-left set to view left + left border width
        //style.left = 0 + "px";
        style.left = (view.l + border.l) + "px";
      } else if (pd.match(/^[tb]c-/)) {
        //MODIFY [top/bottom]-center is view/2 + view left + border left - node/2
        //style.left = Math.round((view.w - nodeSize.w - 1 - view.l)/2)+"px";
        style.left = (Math.round(view.w / 2) + view.l + border.l - (nodeSize.w / 2)) + "px";
      }
      style.clip = "rect(0px, " + nodeSize.w + "px, " + nodeSize.h + "px, 0px)";
      if (has("ie")) {
        if (!this.bgIframe) {
          //MODIFY registry.getUniqueId
          //this.clipNode.id = registry.getUniqueId("dojox_widget_Toaster_clipNode");
          this.clipNode.id = registry.getUniqueId("mods_widget_MapToaster_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);
    }
  });

});

The css:
/* map toaster */
.dijitMapToasterContent {
 padding:0.75em;
 background:#B5BCC7;
 /*background-color:rgb(181,188,199);
 background-color:rgba(181,188,199,0.9);*/
 text-align:center;
 -webkit-border-radius:0px 0px 10px 10px;
 border-radius:0px 0px 10px 10px;
}
.dijitMapToasterMessage{ 
 /*color:#fff;*/
}
.dijitMapToasterWarning,
.dijitMapToasterError,
.dijitMapToasterFatal{
 font-weight:bold;
 color:#fff;
}
.dijitMapToasterWarning .dijitMapToasterContent{
 background:#900;
} 
.dijitMapToasterError .dijitMapToasterContent{
 background:#990;
}
.dijitMapToasterClip {
 position: absolute;
 z-index: 5000;
 overflow: hidden;
}
.dijitMapToasterContainer {
 display: block;
 position: absolute;
 width: 200px;
 margin: 0px;
 /*font:0.75em;*/
}


Create it with the added parameter mapId for the id of the map div, not the map object itself.
app.map.toaster = new mods.widget.MapToaster({ mapId: 'center-map', defaultType: 'message', duration: 3500, positionDirection: 'tc-down' });


Call for it:
app.map.toaster.setContent('Click map to draw point.');


Not generally this forthcoming with stuff like this, but guess what: I clicked on the link in your post and saw myself asking a question that never got answered. Forgot about that. Mine didn't get answered but yours will.
0 Kudos
JeffreySchmidt
Deactivated User
Thank you Ben, I appreciate the help!  I intend to implement this next week.  😉
0 Kudos