Play WebUI Game in IFrame

Playing TADS games on the web was a feature requested for a long time by the community. Now it's finally available, but I've heard mixed feelings about the way it was realized. TADS can't easily be run entirely in browser using JavaScript on client side, instead client-server approach was choosen and although it brings lots of unique possibilities, it seems to be quite hard for many folks from IF community to use its power.

One of the foremost request is to allow players to play my own game on my own website with ease. So let's try:

Yes, that's a simple iframe tag with src pointing to public game server which will run a game file hosted anywhere on the internet:

<iframe src="http://gs.tads.io/?storyfile=http%3A%2F%2Ftads.cz%2Fheidi.web.t3" width="800" height="600"></iframe>

No need to setup you own linux server, no need to pay for it, no need to know daunting technical details! How it is done, how it works?

TADS authors knows that only handful of people will want to do this technical stuff. Personally I run my own game server and I also run my own storage server so players registered on my website can play game (even in group of more than one people over internet togehter) and save positions in the game with ease - game is seamlessly integrated with the website and I also can offer leaderboard so my players can see how far other players are in a game. But for others greatly simplified approach is available.

There is no need to run your own server, TADS community offers a free public cloud service, just link to http://gs.tads.io/?storyfile=url and you can play any web UI game in TADS which is hosted anywhere on internet. IFdb play online button works similar way, but you can add link to your own website too. Only remember to escape characters when writing URL. Every slash becames %2F and colon after http should be changed to %3A. Sorry, game files can't be hosted on https.

Neither there is need for storage server. After save command is typed by the player a save game file will be offered for download and user can store this file locally and upload it later for restore.

But how to embed game to my own website so the players are not redirected away and still see a menu and design and such? You can use an iframe tag instead of a href, but unfortunately it won't work out of box. WebUI in TADS is not designed to be run inside an iframe, some JavaScript errors pops out. The reason lies in cross origin checks and WebUI pays no attention to the fact that top level window is not accessible when inside of iframe.

But this should not to be viewed as a principial problem, it just a little bug and can be fixed. In the directory with source code of your game create a subdirectory named "webuires" in lowercase and also please add -res webuires to your Makefile.t3m. That's a way to override original resources of the WebUI and by the way that's how to tweek any other aspects, like CSS and HTML templates to match your website design. Copy original util.js file from the library there and make following changes and enjoy:

--- util.js.orig        2014-08-03 13:16:01.000000000 +0200
+++ util.js     2018-11-11 11:47:06.000000000 +0100
@@ -14,6 +14,7 @@

 // my page name, as I'm known to the server
 var pageName = "";
+var sameOrigin = false;

 // the generic noun we use to refer to this program in error messages
 // (game, story, program, ...)
@@ -65,7 +66,10 @@
 function utilInit()
 {
     // if we have a parent, ask the parent for my name
-    if (window.parent && window.parent != window)
+    try { sameOrigin = window.parent.location.host == window.location.host; }
+    catch(e) { }
+
+    if (window.parent && window.parent != window && sameOrigin)
         pageName = window.parent.pathFromWindow(window);

     // detect the browser version
@@ -733,7 +737,7 @@

     // if we have a parent window, ask it to look for a default
     var par = window.parent;
-    if (par && par != window)
+    if (par && par != window && sameOrigin)
     {
         // there's a parent window - pass the request up to it
         par.setDefaultFocus(desc, fromWin);
@@ -837,7 +841,7 @@
         closePopup();

     // if we have a parent window, propagate the click
-    if (window.parent && window.parent != window)
+    if (window.parent && window.parent != window && sameOrigin)
         window.parent.popupCloser(ev);
 }

@@ -2986,7 +2990,14 @@
 {
     // find the top-level window
     var w;
-    for (w = window ; w.parent && w.parent != w ; w = w.parent) ;
+    for (w = window ; w.parent && w.parent != w ; w = w.parent)
+    {
+        try
+        {
+            if(w.parent.location.host != w.location.host) break;
+        }
+        catch(e) { break; }
+    }

     // if there's no path, get the top-level window
     if (!path)
@@ -3188,7 +3199,7 @@
 function debugLog(msg)
 {
     // send this to our parent window, if we have one
-    if (window.parent && window.parent != window)
+    if (window.parent && window.parent != window && sameOrigin)
         window.parent.debugLog(msg);
 }

Disclaimer: I'm really lame in JavaScript and this is not tested extensively and it's not a clean solution. I know it works in Chrome 55 on Linux and it displays some weird JS error on TADS console in quite old Firefox, but the game still can be played. The error is quite strange because it's reported on line 0 so I really don't know where should I fix it. But still there could be browser versions where it won't work at all. Please feel free to report and maybe someone better at JS than me will help to enhance this. Please feel free to comment on which browsers it works and not works.