Dynamic Informational Message Box

Use this board to ask questions or have discussions with other Rich Displays users.
Post Reply
DaveLClarkI
Experienced User
Posts: 165
Joined: Wed Dec 11, 2013 10:40 am
First Name: Dave
Last Name: Clark
Company Name: WinWholesale, Inc.
Phone: 937-294-5331
Address 1: 31101 Kettering Blvd.
City: Dayton
State / Province: Outside Canada/USA
Zip / Postal Code: 45439
Country: United States
Contact:

Dynamic Informational Message Box

Post by DaveLClarkI »

We have need of a dynamic informational message box which all of our applications can use. We can't use the widget-based message support built into Profound UI or the screen-based message support because those always show up as error messages.

We may want just an informational message or one that isn't tied to a widget. I know we could manually create such a message box in each screen, but we'd prefer that this be done dynamically just by calling a function in our custom.js file. So, we get to my question...

What would be the recommended means of creating such a dynamic widget within the Profound UI page? Note that I do have advanced JavaScript skills which I can use to create advanced HTML structures on the fly. But, I want this to also work well with Profound UI. Your recommendation? Thanks.
Scott Klement
Experienced User
Posts: 2711
Joined: Wed Aug 01, 2012 8:58 am
First Name: Scott
Last Name: Klement
Company Name: Profound Logic
City: Milwaukee
State / Province: Wisconsin

Re: Dynamic Informational Message Box

Post by Scott Klement »

There are a bunch of different options here. Not exactly sure what you're after? By "widget based message support", I assume you're referring to the "error messages" property on the widgets? Yes, that's always styled as an error message. But, it is hardly the only way to display messages... you could simply use an output field... or an output field on a dialog with an OK button, etc.

So, if you want to drive this from RPG (which is the way most of our customers would do it, and seems the most practical) you could write an RPG program that just takes the message as a parameter... maybe the message type (info, warning, error, whatever) and maybe also returns replies, if that's desired. (I'm thinking like the MessageBox() API in Windows). So this would just be a standalone RPG progam you can CALL when you want to show a message box. The RPG program would have it's own display file with just the one record format you need to display this, and it would have keywords like "assume" and "Show as window" to make it overlay existing screens. This is probably the best approach.

If you wanted to drive this from JavaScript, (which I don't think is ideal here, since the flow of the application may change based on the response, and it just makes more sense to drive the flow of the application from RPG vs. JavaScript) then you could simply use standard DOM calls to whack a div into the screen, position it, etc. Standard dynamic HTML stuff... and return the result from your function so that JS routines could use it... This might make sense if you're coding a lot of the program logic into the display file with JavaScript for some reason.
DaveLClarkI
Experienced User
Posts: 165
Joined: Wed Dec 11, 2013 10:40 am
First Name: Dave
Last Name: Clark
Company Name: WinWholesale, Inc.
Phone: 937-294-5331
Address 1: 31101 Kettering Blvd.
City: Dayton
State / Province: Outside Canada/USA
Zip / Postal Code: 45439
Country: United States
Contact:

Re: Dynamic Informational Message Box

Post by DaveLClarkI »

OK, I've started down the road of a native JavaScript solution. It *is* driven by RPG; but, not directly. There will be a hidden text box which can receive a string of HTML from RPG. In the onload event for the screen, I have this code:

Code: Select all

if (get("htmlMessage") > '')
{
  wob.displayMessageText('', get("htmlMessage"), 3000, 'mouse');
}
The reason for the empty first parm is because this function will serve double-duty. The first parm is for a widget id that the programmer chose to code directly into their screen. Thus, if a value for that parm is omitted, then the function will build its own, dynamic widget. The third parm is for a jQuery fadeout() and the fourth parameter is for positioning. Options include 'top', 'bottom', 'left', 'right', and 'center' in addition to the 'mouse' option shown.

Still working on the positioning, but this is what I have for building it so far:

Code: Select all

		dyno = document.createElement("div");	// then, (re)create it
		dyno.setAttribute("id", dynoId);
		dyno.setAttribute("class", "dropShadow");
		dyno.style.position = "absolute";
		dyno.style.left = "0px";
		dyno.style.top = "0px";
		dyno.style.background = "no-repeat white";
		dyno.style.border = "3px solid green";
		dyno.style.borderRadius = "3px";
		dyno.style.font = "bold normal 12px 'Arial, sans-serif'";
		dyno.style.padding = "0px 5px 5px 0px";	// bottom, left, right, top
		dyno.style.width = "200px";
		dyno.style.zIndex = "200";
		dyno.innerHTML = messageText;			// set value of dynamic widget
		getObj("5250").appendChild(dyno);		// add to page
		$("#" + dynoId).fadeOut(fadeDuration);	// jQuery method to fade object
Note that I am placing it in the "5250" container. What is the name of the container when there is no Genie session? ...or, is there a PUI-provided means of obtaining the container name currently in use so that I don't have to hard-code it? Thanks.
User avatar
David
Profound Logic Staff Member
Posts: 690
Joined: Fri Jan 04, 2008 12:11 pm
First Name: David
Last Name: Russo
Company Name: Profound Logic Software
Contact:

Re: Dynamic Informational Message Box

Post by David »

You'll want to use 'pui.runtimeContainer', rather than referencing the div "5250" by id. The div is called something else when running outside of Genie. This property always has a reference to the correct div element, regardless of how you run the session.
DaveLClarkI
Experienced User
Posts: 165
Joined: Wed Dec 11, 2013 10:40 am
First Name: Dave
Last Name: Clark
Company Name: WinWholesale, Inc.
Phone: 937-294-5331
Address 1: 31101 Kettering Blvd.
City: Dayton
State / Province: Outside Canada/USA
Zip / Postal Code: 45439
Country: United States
Contact:

Re: Dynamic Informational Message Box

Post by DaveLClarkI »

So I can code the following?

Code: Select all

pui.runtimeContainer.appendChild(dyno);      // add to page
DaveLClarkI
Experienced User
Posts: 165
Joined: Wed Dec 11, 2013 10:40 am
First Name: Dave
Last Name: Clark
Company Name: WinWholesale, Inc.
Phone: 937-294-5331
Address 1: 31101 Kettering Blvd.
City: Dayton
State / Province: Outside Canada/USA
Zip / Postal Code: 45439
Country: United States
Contact:

Re: Dynamic Informational Message Box

Post by DaveLClarkI »

I tried that and it is working. Thanks.
DaveLClarkI
Experienced User
Posts: 165
Joined: Wed Dec 11, 2013 10:40 am
First Name: Dave
Last Name: Clark
Company Name: WinWholesale, Inc.
Phone: 937-294-5331
Address 1: 31101 Kettering Blvd.
City: Dayton
State / Province: Outside Canada/USA
Zip / Postal Code: 45439
Country: United States
Contact:

Re: Dynamic Informational Message Box

Post by DaveLClarkI »

If anyone is interested, I'm attaching the code I created for this. It can be used in three ways -- to load and animate an existing message widget defined in the page, to animate a dynamic widget driven from your RPG code, and to animate a dynamic widget driven by JavaScript only. There is also a couple of CSS definitions that go with it. Lastly, jQuery™ is required for the fade animation effects.

NOTE: "wob" is the name of our Genie skin so you can change that part to what you want.

To use the dynamic widget driven from your RPG code, you can use something similar to the following in your screen "onload" event -- which this code uses txtMessage as a hidden text box bound to your RPG.

Code: Select all

wob.displayMessageText(null, getObj("txtMessage"), 0, 'center');
To use the dynamic widget driven by JavaScript only, the following is an example using the grid onrowclick event. In my case, the function I call here is one which counts the currently selected grid rows and if more than one is selected the dynamic message function is called.

Code: Select all

window.setTimeout(function()
{
  var cnt = wob.countGridRowSelections("ACLKUV1S", "*IN30");
  if (cnt > 1)
  {
    changeElementValue("txtMessage", cnt + " selections active.");
    wob.displayMessageText(null, getObj("txtMessage"), 0, "mouse", event);
  }
}, 100);
These are the CSS definitions:

Code: Select all

.dropShadow {
  -moz-box-shadow:    5px 5px 3px #333;
  -webkit-box-shadow: 5px 5px 3px #333;
  box-shadow:         5px 5px 3px #333;
}

#dynoInfoBox {
  background:    no-repeat white;
  border:        3px solid green;
  border-radius: 3px;
  color:         black;
  font-family:   Arial, sans-serif;
  font-size:     12px;
  font-weight:   bold;
  padding:       5px 10px 5px 10px; /* top, left, bottom, right */
  z-index:       200;
}
These are all the functions required:

Code: Select all

/*	================================================================================
	displayMessageText()	sets the value of a widget to the specified message text,
							makes the widget visible, and then fades the widget to
							invisibility -- ready for the next go-round.  If you do
							NOT want a fade effect, specify -1 for the fade duration.
							Optionally, the first parm can be supplied as null and
							this causes a dynamic message box to be built, displayed,
							and faded automatically.  The position and event parms
							apply only to this dynamic message box; where: position
							can be specified as 'center', 'top', 'bottom', 'left',
							or 'right'.  Alternatively, if there is an associated
							mouse event, then position may be specified as 'mouse'
							to align the popup message with the mouse at the time
							the mouse event occurred.  Supply the event object parm
							in this case.
*/
wob.displayMessageText = function(widgetId, msgSource, fadeDuration, position, event)
{
	var messageText = get(msgSource.id);	// get any message text
	changeElementValue(msgSource.id, "");	// clear any message text
	if (messageText <= " ") return;			// if no message text, then exit

	var fadeDefault = 2000 + (Math.ceil((messageText.split(/\s+/)).length / 2) * 1000); 
	fadeDuration = (fadeDuration) ? fadeDuration : fadeDefault; // set default if missing
	if (widgetId)							// if Profound widget identified
	{
		changeElementValue(widgetId, messageText);			// set value of widget
		applyProperty(widgetId, "visibility", "visible");	// show the widget
		$("#"+widgetId).fadeIn(0);							// jQuery method to show object
		if (fadeDuration > 0)								// if fade out requested
		{
			$("#"+widgetId).fadeOut(fadeDuration);			// jQuery method to fade object
		}
	}
	else									// else, create dynamic widget
	{
		fadeDuration = (fadeDuration > 0) ? fadeDuration : fadeDefault; // force a fadeout
		position = (!position) ? 'center'
				 : (event && position == 'mouse') ? position
				 : (('top,bottom,left,right,center').indexOf(position) > -1) ? position
				 : 'center';					// need a default position?
		var offsets = wob.getContainerOffsets(msgSource.parentNode, event);	// get page and mouse offsets
		var dynoId = "dynoInfoBox";				// set id of dynamic widget
		var dyno = document.getElementById(dynoId);	// get pointer to dynamic widget
		if (dyno && dyno.id == dynoId)			// if dynamic widget already exists
		{
			dyno.parentNode.removeChild(dyno);		// trash it
		}
		dyno = document.createElement("div");	// then, (re)create it
		dyno.setAttribute("id", dynoId);
		dyno.setAttribute("class", "dropShadow");
		dyno.style.position = "absolute";
		dyno.style.left = "300px";
		dyno.style.top = "200px";
		if (messageText.length > 50)			// if this is a long message
		{
			dyno.style.width = "280px";			// limit width of message box
			dyno.style.whiteSpace = "pre-wrap";	// and perform word wrap
		}
		else									// else default width to length of text
		{
			dyno.style.whiteSpace = "nowrap";	// and no word wrap
		}
		dyno.style.visibility = "hidden";		// initial setting to allow repositioning
		dyno.innerHTML = '<img style="float: none; width: 16px; height: 16px; vertical-align: text-bottom;"'
					   + ' src="/profoundui/proddata/images/icons/information.png"></img> ';
		dyno.innerHTML += messageText;			// set value of dynamic widget
		dyno = msgSource.parentNode.appendChild(dyno);	// add to container
		switch (position)
		{
			case 'mouse':
				dyno.style.left = (offsets.mouseLeft + 10) + "px";
				dyno.style.top = (offsets.mouseTop - dyno.offsetHeight - 10) + "px";
				break;
			case 'center':
				dyno.style.left = (Math.floor(offsets.width / 2) - Math.floor(dyno.offsetWidth / 2)) + "px";
				dyno.style.top = (Math.floor(offsets.height / 2) - dyno.offsetHeight) + "px";
				break;
			case 'top':
				dyno.style.left = (Math.floor(offsets.width / 2) - Math.floor(dyno.offsetWidth / 2)) + "px";
				dyno.style.top = "5px";
				break;
			case 'left':
				dyno.style.left = "5px";
				dyno.style.top = (Math.floor(offsets.height / 2) - dyno.offsetHeight) + "px";
				break;
			case 'bottom':
				dyno.style.left = (Math.floor(offsets.width / 2) - Math.floor(dyno.offsetWidth / 2)) + "px";
				dyno.style.top = (offsets.height - dyno.offsetHeight - 5) + "px";
				break;
			case 'right':
				dyno.style.left = (offsets.width - dyno.offsetWidth - 5) + "px";
				dyno.style.top = (Math.floor(offsets.height / 2) - dyno.offsetHeight) + "px";
				break;
			default:
		}
		dyno.style.visibility = "visible";
		$("#" + dynoId).fadeIn(0).fadeOut(fadeDuration);	// jQuery method to fade object
	}
}

/*	================================================================================
	getContainerOffsets()	returns an object describing various dimension and
							position attributes for the specified container object.
							Optionally, if the event object parameter is passed, the
							returned object also includes adjusted mouse offsets.
*/
wob.getContainerOffsets = function(container, event)
{
	var offsets = wob.browserPageOffsets();		// get scrolled offset of page
	offsets.client = wob.browserClientArea();	// get client area of page

	var ele = container;   						// starting from the container
	do					   						// calculate container's offsets
	{
		offsets.left += ele.offsetLeft;				// include left offset
		offsets.top += ele.offsetTop;				// include top offset
	}
	while (ele = ele.offsetParent);				// which includes all offset parents

	var coord = pui.getDimensions(container);	// get coordinates of effective container dimensions
	offsets.width = coord.x2 - coord.x1;		// calculate container width
	offsets.height = coord.y2 - coord.y1;		// calculate container height

	if (event)									// if an event object was included
	{											// then set offset for mouse coordinates
		offsets.mouseLeft = getMouseX(event) - offsets.left;
		offsets.mouseTop = getMouseY(event) - offsets.top;
	}

	return offsets;								// return offsets to caller
}

/*	================================================================================
	browserClientArea()	returns the width and height of the displayable area of the
						browser page that does not require scrolling.
*/
wob.browserClientArea = function()
{
	if (document.documentElement
	&& typeof document.documentElement.clientWidth != 'undefined')
	{
		return { width: document.documentElement.clientWidth,
				height: document.documentElement.clientHeight };
	}
	if (typeof self.innerWidth != 'undefined')
	{
		return { width: self.innerWidth,
				height: self.innerHeight };
	}
	if (document.body
	&& typeof document.body.clientWidth != 'undefined')
	{
		return { width: document.body.clientWidth,
				height: document.body.clientHeight };
	}
	return null;
}

/*	================================================================================
	browserPageOffsets()	returns the left, top, width, and height offsets of the
							scrolled browser page: where, left and top will be zero
							if the page is not scrolled.
*/
wob.browserPageOffsets = function()
{
	if (document.documentElement
	&& typeof document.documentElement.scrollTop != 'undefined')
	{
		return { left: document.documentElement.scrollLeft,
				  top: document.documentElement.scrollTop,
				width: document.documentElement.scrollWidth,
			   height: document.documentElement.scrollHeight };
	}
	if (typeof self.pageXOffset != 'undefined')
	{
		return { left: self.pageXOffset,
				  top: self.pageYOffset,
				width: document.width,
			   height: document.height };
	}
	if (document.body
	&& typeof document.body.scrollLeft != 'undefined')
	{
		return { left: document.body.scrollLeft,
				  top: document.body.scrollTop,
				width: document.body.scrollWidth,
			   height: document.body.scrollHeight };
	}
	return null;
}
Last edited by DaveLClarkI on Fri Jan 24, 2014 10:52 am, edited 2 times in total.
DaveLClarkI
Experienced User
Posts: 165
Joined: Wed Dec 11, 2013 10:40 am
First Name: Dave
Last Name: Clark
Company Name: WinWholesale, Inc.
Phone: 937-294-5331
Address 1: 31101 Kettering Blvd.
City: Dayton
State / Province: Outside Canada/USA
Zip / Postal Code: 45439
Country: United States
Contact:

Re: Dynamic Informational Message Box

Post by DaveLClarkI »

The above post has been corrected as a result of new things I've learned in this process.
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests