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 POST
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
//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.');