Solved! Go to Solution.
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 POSTdefine([ "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
//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);
}
});
});/* 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;*/
}app.map.toaster = new mods.widget.MapToaster({ mapId: 'center-map', defaultType: 'message', duration: 3500, positionDirection: 'tc-down' });app.map.toaster.setContent('Click map to draw point.');