Step by Step Gas Publisher

In Gas Publisher I described the detail of how the Gas Publisher works. Although most of the code is in the shared mcpher library,  there is some set up you have to do in your own projects. There is no coding to do – just attaching to libraries and a bit of cut and paste. Here’s the schematic again to remind you of what we are trying to do. 

 

Creating a publisher

This is the publisher that will be exposed publicly, and you need to publish as a web app. All requests will be dealt with through this single doGet(e) function. You can copy a ready made one from here. That will cover these steps. Remember that everything is case sensitive.
   
// used by template
var eArgs;
 /** publish google apps script in various formats
  * all apply to e.parameter..
  * @param {String=} module the name of the module|scriptdb|gistfilename|filename entry to publish
  * @param {String=} library the name of the attached library|gistId that contains the module (blank/missing = local)
  * @param {String=} type the type of output required (json|html|js|jsonp|javascript) 
  * @param {String=} template the template to use - must exist in this script 
  * @param {String=} callback required for jsonp otherwise you get json
  * @param {String=} source where it comes from script|scriptdb|custom|gist|web
  * @param {String=} func comma seperated list of functions to include .. default is all
  * @param {String=} query json query to be used along with scriptdb
  * @return {object} depends on format selected
 */

function doGet(e) {

    //----------
    // need to put this in a global var for callback from template
    eArgs = e;
    // set the arg defaults
    mcpher.setGasPubDefaults (eArgs);
    // convert source to correct format
    var result = expressSource(eArgs);

    // publish as appropriate
    return mcpher.prepareGasPub(eArgs,result);
}

 /* convert source code to required format
  * @param {object} e arg to doGet(e)
  * @return {object} the source expressed according the format
  */
function expressSource(e) {
  // if a template is mentioned, we are going to do html
  if (mcpher.isNeedTemplate (e)) {
    // evaluate the template
    try {
      var template = HtmlService.createTemplateFromFile(e.parameter.template);
      return template.evaluate().getContent(); 
    }
    catch (err) {
      return  { error: 'error ' + err + 'reading template' + e.parameter.template};
    }
  }
  else {
    // this going to be Json or jSonP or javascript
    return getSource();
  }
}
 /** gets the appropriate source for the combination of requested module and requested library
  * @param {String} content the web content 
  * @return {String} the escaped content
  */
function getSource() {
  return getMySource(eArgs);
}

// -- write a getMySource() to retrieve any modules in THIS script file
/* Returns a modules source code
 * @param {parameters} e the argument to doGet(e). should have module parameter specified
 * @return {object} The result.
 */

function getMySource(e) {
  // probably doesnt need changed, except if you need a custom function
  // the purpose of all this is to execute the scriptdb/scriptapp in the correct project according to the library selected
    
  // maybe muliple modules - introduced this hack to speed up hosting javascript code
      var modules =[]; 
      if (e.parameter.module && e.parameter.type && e.parameter.type == "javascript") 
          modules = e.parameter.module.split(",");
      
      var r;
      if (modules.length > 1) {
        try {
          var cum = "";
          for (var i=0;i<modules.length;i++) {
            e.parameter.module=modules[i];
            r = getMyMod(e);
            if (r.error) break;
            cum +=r.results.data;
          }
          // subsititute the result with cumulative results
          if(r.results) r.results.data = cum;
          
       }
       catch(err) {
        return { error : err + " when trying to get module ", parameters : e.parameter };
       }
      }
      else {
        r = getMyMod(e);
      }
        
      return r;
}
// -- write a getMySource() to retrieve any modules in THIS script file
/* Returns a modules source code
 * @param {parameters} e the argument to doGet(e). should have module parameter specified
 * @return {object} The result.
 */
function getMyMod(e) {
  // probably doesnt need changed, except if you need a custom function
  // the purpose of all this is to execute the scriptdb/scriptapp in the correct project according to the library selected
    try {
      return mcpher.getGeneralSource(e,
              e.parameter.source == 'script' ? 
                eval(mcpher.addLibraryPrefix(e,"showMyScriptAppResource"))(e.parameter.module) :
                ( e.parameter.source == 'scriptdb' ? 
                  eval( mcpher.addLibraryPrefix(e,"showMyScriptDb"))() : null
                 ) ,
              function (e) { // this is a custom function if you need one 
                         return null;} 
            );
    }
    catch (err) {
      return { error : err + " when trying to get module ", parameters : e.parameter };
    }
}
  • Create default templates called js & html, or use the copied ones. I havent found out how to get the source of templates yet, so these are just pasted in. 
 

html template

<html>
<head>
<script src=”https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js” type=”text/javascript”></script>
<link href=”http://caja.appspot.com/prettify.css” type=”text/css” rel=”stylesheet” />
<link href=”http://xliberation.com/p/css/gaspub.css” type=”text/css” rel=”stylesheet” />
<script src=”http://caja.appspot.com/prettify.js” type=”text/javascript”></script>

<script>
$(document).ready(function () {
// any jQueryness can happen here…
var thingsThatScrewUp = [ ‘toString’, ‘hasOwnProperty’],t;

$(‘.pretty’).each( function(i,elem) {
var c = $(elem).text() ;
// disguise
for (var i = 0 ; i < thingsThatScrewUp.length ; i++ ) {
c = c.replace(new RegExp(“.” + thingsThatScrewUp[i], ‘g’),”.sandw_” + i + “_ch”);
}
try {
t = prettyPrintOne(c);
}
catch (err) {
$(‘#report’).html(err + c);
}
// undisguise
for (var i = 0 ; i < thingsThatScrewUp.length ; i++ ) {
t = t.replace(new RegExp(“sandw_” + i + “_ch”, ‘g’),thingsThatScrewUp[i]);
}
$(elem).html(“<pre class=’code pretty prettyprint’>” + t + “</pre>”);
});
$(‘#working’).html(‘Module:’);
});

</script>
</head>
<body>
<div>
<? var content = getSource(eArgs); ?>
<? if (content.error) {
var errors = JSON.stringify (content, null , 2 ) ; ?>
<div class = “error”>
<?= errors ?>
</div>
<? } else { ?>
<div class = “module”><span id=”working”>working on … </span>
<?= content.parameters.module ?>
</div>
<div class = “code pretty”><pre class=”prettyprint lang-js”><?= content.results.data ?></pre>
</div>
<? } ?>
</div>
<div id=”report”></div>
</body>
</html>

js template

<div>    
  <? var content = getSource(eArgs); ?>
  <? if (content.error) { 
    var errors = JSON.stringify (content, null , 2 ) ; ?>
    <div class = “error”>
     <?= errors ?>
    </div>
    <? } else  { ?>
  <div class = “module”><span id=”working”>Module: </span>
   <?= content.parameters.module ?>
  </div>   
  <div class = “code pretty”><pre class=”prettyprint lang-js”><?= content.results.data ?></pre>
  </div>
    <? } ?>
  </div>
<div id=”report”></div>
</body>
</html>
 

Attach any projects you want to access as libraries. You will need to create these functions (just copy them in as is) somewhere in every project that you want to be able to access from the publisher. This is because it needs to be able to get the scriptdb and scriptapp instance of the library it is reporting on and these are only accessible from the library itself. It will need these to exist to be able to access them.


function showMyScriptDb() {
  return publicStuffDb();
}
function showMyScriptAppResource(s) {
  try {
    return ScriptApp.getResource(s);
  }
  catch (err) {
    throw err + " getting script " + s;
  }
}
function publicStuffDb() {
  return ScriptDb.getMyDb();
}
  • Publish your Publisher project as a web app, allowing anybody to access, including anonymouse. This is public data remember.  For a reminder on how to do this see Hosting your public scriptdb

 

  • Create your own container script and host it on dropbox or somewhere if you plan to use gadgets for embedding. You should tweak the defaults to reflect the Url of your public app. Or, you can use my one and pass your url as an argument.  See GAS Publisher and copy the example from there.

Container

You are done. You can now publish and embed scriptdb and script data without worrying about cross domain stuff.  

For help and more information join our forum, follow the blog or follow me on twitter . For more on Google Apps Script try Delegation to Google Apps Script or Gas Publisher.

Find more Step by Step guides: