Your SAS programs, embedded in web apps and elsewhere

STP javascript generation 9.3 vs 9.4

Accepted Solution Solved
Reply
PROC Star
Posts: 1,322
Accepted Solution

STP javascript generation 9.3 vs 9.4

I'm inserting some basic javascript into a long running stored process to generate a "Please Wait" message that should appear at the beginning of a long-running stored process and then be hidden at the end, using a method from Don Henderson: http://www.sascommunity.org/wiki/Generating_Descriptive_Please_Wait_Messages_for_Long_Running_Stored...

 

The approach has been working fine for me on a  9.3 server, but I'm now migrating it to a 9.4 server, and the "please wait" message is appearing, but is not being hiddden after results are generated.  The stored process generates streaming results, and is being consumed in Internet Explorer and Chrome.

 

Here's sample code:

 

%stpbegin()

data _pleasewait;
  length msg $75;
  msg = "Please Wait"; output;
  msg = "<img src=""/SASStoredProcess/images/progress.gif"">";  output;
run;

ods html text = "<span id=""pleaseWait"">";
proc report data = _pleaseWait nowd;
  columns msg;
  define msg / " ";
run;
ods html text = "</span>";

data _null_;
  x=sleep(3000); *sleep 3 seconds;
run;

proc print data=sashelp.class;
run;

ods html text = "<script>pleaseWait.style.display = ""none""</script>";

%stpend()

 

I compared the two html files, and other than font styling differences, the main difference I see is that in 9.3 the ods html text appears inside DIV tags, and in 9.4 it appears inside of table tags.

 

So in 9.3 at the end I get:

<div class="l usertext"><script>pleaseWait.style.display = "none"</script></div>

And in 9.4 I get:

 

<td class="l usertext"><script>pleaseWait.style.display = "none"</script></td>

 

 

Would be grateful for suggestions on how to get this working in 9.4. 


Accepted Solutions
Solution
‎04-07-2016 10:18 AM
Frequent Contributor
Posts: 106

Re: STP javascript generation 9.3 vs 9.4

Yeah you're right on. This is what I meant when I suggested I'd probably modify the stpbegin and stpend macros, so that you could maybe have the span as the first element of the body, and the script as the last bit of it. The thing is, it kinda annoyed me after I posted it, because I changed my mind on whether it'd be doable. 

 

I had a bit more of a look at it and it'd be hacky and virtually impossible to make it all work with decent html, because of having no way to interrupt the ods stream before the </html> tag to inject the code. You could maybe change the ods html config in %STPBEGIN to include an option for NO_BOTTOM_MATTER and then code up the closing statements in %STPEND yourself, but like I say, hacky.

 

You could try this with your original code. Not great but it's as standards-friendly as I can think of:

 

%stpbegin()

data _pleasewait;
  length msg $100;
  msg = '<div id="pleaseWait">Please Wait<br><img src="/SASStoredProcess/images/progress.gif"></div>';
  output;
run;

proc report data = _pleaseWait nowd;
  columns msg;
  define msg / " ";
run;

data _null_;                                    
  x=sleep(3000); *sleep 3 seconds;
run;

proc print data=sashelp.class;
run;
ods html text='</td></tr></table><script>pleaseWait.parentNode.style.display = "none"</script><table><tr><td>';

%stpend()

I'm still not a big fan of it :/

View solution in original post


All Replies
PROC Star
Posts: 1,322

Re: STP javascript generation 9.3 vs 9.4

Found this post from @Eva, who also had problems migrating to 9.4 caused by the change to have the ODS TEXT statement write html text inside of tables instead of <DIV> tags. : https://communities.sas.com/t5/ODS-and-Base-Reporting/ods-html-text-in-SAS-9-4/td-p/224909

 

From the responses there, it looks like there is no easy way to get 9.4 to revert to writing text in <DIV> tags .  (Unless you found one, Eva?)  Maybe it wouldn't be that hard to muck with the tagset? (I can't remember if there is an editable tagset in 9.4, or if this was essentially locked down by the switch to Lua?)

 

For those who know about javascript, does it make sense that having the javascript code appear inside of tables would break it ? 

 

Perhaps instead of using ODS HTML statements, I should use try adding PREHTML and POSTHTML to the style template, as in: http://support.sas.com/resources/papers/proceedings14/1673-2014.pdf and see if that avoids the <table> tags.

Regular Contributor
Regular Contributor
Posts: 156

Re: STP javascript generation 9.3 vs 9.4

I added my solution to the original post. Please see there.

PROC Star
Posts: 1,322

Re: STP javascript generation 9.3 vs 9.4

Thanks @Eva.  Unfortunately, I couldn't get the data _null_   PUT statement approach to work.   It still put the values into HTML tables.  Titles and footnotes also went into tables. 

 

But I was able to get it working by using the new (I think) PROC ODSTEXT.

 

Here's my proof-of-concept:

 

%stpbegin()

*Create PleaseWait message;

proc odstext;
  p "<span id=""pleaseWait"">
     Please Wait <p>
     <img src=""/SASStoredProcess/images/progress.gif"">
     </span>
    "
  ;
run;

*Main part of STP;
data _null_;
  x=sleep(3000); *sleep 3 seconds;
run;

proc print data=sashelp.class;
run;


*Hide the Pleasewait message;

proc odstext;
  p "<script>pleaseWait.style.display = ""none""</script>";
run;

%stpend()

 

 

 

I think something like that will work for my needs (will wrap in a %PleaseWait macro, as in Don's post).  But happy to hear of any other solutions. 

Frequent Contributor
Posts: 106

Re: STP javascript generation 9.3 vs 9.4

Hey Quentin,

 

This is one possible approach:

 

 

data _null_;
  file _webout;
  put '<span id="pleaseWait" style="display:table;margin:0 auto;text-align: center;">';
  put "Please Wait<br>"; 
  put '<img src="/SASStoredProcess/images/progress.gif">';
  put "</span>";
run;

%stpbegin()


data _null_;
  x=sleep(3000); *sleep 3 seconds;
run;

proc print data=sashelp.class;
run;


%stpend()

data _null_; 
  file _webout;
  put '<script>pleaseWait.style.display = "none"</script>';
run;

 

As you know, you could also modify the stpbegin/stpend macros to insert this code, and apply it universally. Or, you could stream in the full contents of an external file with a CSS/JS based spinner, and make it all a lot prettier using SVG spinners etc. Or, as you say, you could use PREHTML and POSTHTML. I'd avoid that though, as you'd have to do it every single time.

 

Personally I'd clone my stpbegin/stpend macros and modify them to blanket include an external file with a nicer customised corporate logo SVG/javascript based spinner.  %stpbegin_spinner and %stpend_spinner. Oh the possibilities are endless... Smiley Happy

 

Having <script> tags inside other HTML content isn't great practice.

 

 

Nik

PROC Star
Posts: 1,322

Re: STP javascript generation 9.3 vs 9.4

Posted in reply to boemskats

Thanks @boemskats.  Was expecting to hear from you, and you came through yet again. : )

 

Great that this keeps the scripting completely outside of the HTML body.  That should keep me from mucking up any of my output.

PROC Star
Posts: 1,322

Re: STP javascript generation 9.3 vs 9.4

[ Edited ]
Posted in reply to boemskats

Hi again @boemskats

 

I like that your approach works, but is this really valid html, to put a <span> tag before even the <html>, and the script after </html> ?

 

I get html like:

<span id="pleaseWait" style="display:table;margin:0 auto;text-align: center;">
Please Wait<br>
<img src="/SASStoredProcess/images/progress.gif">
</span>
<html>
  <head>
  </head>
  <body>
  </body>
</html>
<script>pleaseWait.style.display = "none"</script>

 

And from a bit of googling (e.g. http://stackoverflow.com/questions/3037725/is-it-wrong-to-place-the-script-tag-after-the-body-tag), looks like folks generally agree that that script should be just before the closing </body> tags, and having the <span> etc before the opening <html> is probably invalid also, right? 

 

That said, it works (at least in IE), and I've been known to generate invalid HTML in the past, so if you think it's likely this will work for a reasonable amount of time before breaking again, I'll probably go with it it. : )

Solution
‎04-07-2016 10:18 AM
Frequent Contributor
Posts: 106

Re: STP javascript generation 9.3 vs 9.4

Yeah you're right on. This is what I meant when I suggested I'd probably modify the stpbegin and stpend macros, so that you could maybe have the span as the first element of the body, and the script as the last bit of it. The thing is, it kinda annoyed me after I posted it, because I changed my mind on whether it'd be doable. 

 

I had a bit more of a look at it and it'd be hacky and virtually impossible to make it all work with decent html, because of having no way to interrupt the ods stream before the </html> tag to inject the code. You could maybe change the ods html config in %STPBEGIN to include an option for NO_BOTTOM_MATTER and then code up the closing statements in %STPEND yourself, but like I say, hacky.

 

You could try this with your original code. Not great but it's as standards-friendly as I can think of:

 

%stpbegin()

data _pleasewait;
  length msg $100;
  msg = '<div id="pleaseWait">Please Wait<br><img src="/SASStoredProcess/images/progress.gif"></div>';
  output;
run;

proc report data = _pleaseWait nowd;
  columns msg;
  define msg / " ";
run;

data _null_;                                    
  x=sleep(3000); *sleep 3 seconds;
run;

proc print data=sashelp.class;
run;
ods html text='</td></tr></table><script>pleaseWait.parentNode.style.display = "none"</script><table><tr><td>';

%stpend()

I'm still not a big fan of it :/

PROC Star
Posts: 1,322

Re: STP javascript generation 9.3 vs 9.4

Posted in reply to boemskats

Thanks again Nik,

ods html text='</td></tr></table><script>pleaseWait.parentN​ode.style.display = "none"</script><table><tr><td>';

That looks like a good way to avoid the <td> and <tr> tags that are being generated.  Not pretty, but should get the job done.   And all of this unprettiness will at least be hidden in a macro of one sort or the other, so I can comment it there and not look at again until the next time it breaks. : )

 

 

Thans again.  See you in Vegas. 

 

(Fair warning:  50% chance I'll start another thread today or tomorrow, about another thing you helped me with a couple years ago, that I'm also struggling a bit to get working like I want in 9.4... )

Frequent Contributor
Posts: 106

Re: STP javascript generation 9.3 vs 9.4

You're welcome Quentin. Where's this other thread though? You can't say that and then just not post it...

PROC Star
Posts: 1,322

Re: STP javascript generation 9.3 vs 9.4

Posted in reply to boemskats

Hi Nik,

 

Well I said 50% chance of posting my second issue, right?  Smiley Tongue   I figured it out, but happy to share my dumb mistake.  It was one of those debugging sessions which ends with a big self-imposed smack to the head...

 

As background, the STP I was testing on 9.4 generated the please wait message and then generated an <iframe> used to call a second stored process that actually returned results.  This is my implementation of the approach you helpfully described here: https://communities.sas.com/t5/SAS-Stored-Processes/Stored-process-writing-to-the-browser-and-excelx...

 

On 9.4 I had two problems: the javascript to hide the please wait message after completion wasn't working; and the iframe had the wrong height (5 cm instead of 100%).

 

This thread resolved the javascript problem.  In 9.4 the ODS HTML TEXT ended up in a table, and broke my javascript.  The next day I came back to debugging the height, and my process was:

 

  1. Look at the code generating the iframe.  Looks fine.  Been using it for a couple years, no problems. 
  2. Play with the code generating the iframe.  If I changed height from 100% to 500%, the height got larger, which was good.  But 100% should have worked.
  3. Googled a bit about iframes.  Learned that 100% height specification is relative to the parent (?) which holds the iframe.  And depends in part on how the height of the parent is defined.
  4. Since my STP is running the default Stored Process Web App frameset, I thought "well, maybe SAS changed how that frameset is defined in 9.4".
  5. Explored the source html for the SPWA frameset in 9.4, compared it to the source html for the frameset in 9.3.  Saw some differences, none of them explained why my height wouldn't work.
  6. Thought "Well, time for me to make a little example of a simple STP that returns an iframe with height set to 100% to post as a new thread and ask why the height is only 5cm."
  7. Wrote the MakeIframe STP, ran it in 9.4, and the height was not 5cm, it was 100%.
  8. Stared at my computer screen.  "Why did you work?  How is MakeIframe STP different than my original STP?"
  9. Looped back to step #1.  Look at my orginal STP, at the code generating the iframe.
  10. Slap myself in the head.

In my MakeIframe test STP where the height worked, I generated the iframe with a simple data _null_ step and PUT statements. In my original STP where the height did not work, I generated the html code for the iframe with, of course, an ODS HTML TEXT statement.   So in 9.4 the iframe is generated inside of a <table>, causing it to get a shortened height (I assume inherited from the table).  When it's not in a <table> the iframe height of 100% works fine.

 

So despite the fact that these two problems had the exact same root cause, I stil managed to spend as much time debugging the height issue as I did the javascript issue.  All because on step 1 above, my brain didn't look at ODS HTML TEXT="<iframe>....</iframe>"; and think "gee, is there anything I just learned today about ODS HTML TEXT in 9.4?"

 

On the plus side, it was a good reminder that one of the benefits of online communities is that when you take the time to make a good minimal test case to post as a question, often that test case illuminates the problem enough to provide a solution.  And a self-slap to the head.

 

Frequent Contributor
Posts: 106

Re: STP javascript generation 9.3 vs 9.4

[ Edited ]

These things happen, I just don't normally admit to them so publicly!

When you've got some I recommend you spend it getting to grips with the Inspector bit of the developer console of one of the better browsers (Chrome/FF, I prefer the Chrome one). It'll help you wrap your head around a lot of the layout/elements and make this kind of debugging much easier, as you can test your layouts just by editing the css attributes of various elements on the fly...

☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 11 replies
  • 762 views
  • 2 likes
  • 3 in conversation