Version 4, last updated by slim at Mar 18 21:27 2007 UTC

Dynamically constructs an infotron from an HTML blueprint. It can also destruct the constructed infotron.

Sample Declaration

<div id=""
     impl=""
     properties=""
     script=""></div>

Input Terminals

Output Terminals

Properties

Demos that use it

  • dynamic_construction.html

How does it work?

Source


/*
  Mishmash of old and new code - need to think this better
  and how atomic construction and this can become one and the same

  intput_termials
      request - <type:array>
          [id, op, arg1, arg2, ...]

	  op
	     ["construct", bp_uuid, intrinsic_props, extrinsic_props]

  output_terminals
      response - <type:array>
          [id, op, response1, response2, ...] or [[op, response1, response2, ...], id]

  properties
      auto_detects_uri - <type: boolean>
      uses_blueprint_uuid_as_uri - <type: boolean>
      

  Seung Chan Lim ( slim@maya.com )
 */
BLUEPRINT(
"~01A405A30A314F45feA6C35668FF7819E6",
[
 ["request_in", "onRequest", 10]
],
[
 "response_out"
],
function()
{
  var Blueprint = function(id, props, bp_uuid)
    {
      this.__init__(id, bp_uuid);


    /*************************************************************************/
    this._URI_REGEX = new RegExp("^([a-zA-Z]+://)|(mailto:)");
    this._REQ_HANDLER = {construct: this._add,
                        destruct : this._remove};
    this._NON_ATOMIC_BP = "~01F6227AA626384b31850C90E63C829313";
    this._req_id = {}; // keeps track of request id's associated with child
                      // construction
    this._detect_uri = props["auto_detects_uri"];
    this._bp_as_uri = props["uses_blueprint_uuid_as_uri"];
    this._n = 0;
    this._ids = {};
    };

  Blueprint.prototype = new Infotron;

    // override default handling


    /*************************************************************************/
    Blueprint.prototype._onChildError = function(id, msg)
    {
	var resp = ["construct_failed", msg];
	this.error("Failed to construct " + id + "[" + msg + "]");

	if (this._req_id[id] != undefined) {
	    resp = [resp, this._req_id[id]];
	    delete this._req_id[id];
	}

	this.postMessage("response_out", resp);
    }

    Blueprint.prototype.onRequest = function(msg)
    {
	var op, id, e;
	id = msg[0];
	op = msg[1];

	// request handlers return a unique id that request id's
	// can be associated with
	try {
	  var resp = this._REQ_HANDLER[op].apply(this, [id].concat(msg.slice(2)));
	} catch (e) {
	    this.error(e, "Error handling " + op);

	    return;
	    /*****************************************************************/
	}

	if (id != undefined) {
	    
	    // keep track of request id associated with the response
	    this._req_id[resp] = id;
	}
    }


    Blueprint.prototype._createUid = function()
    {
	var id, now = new Date();
	
	while (1) {
	    id = this.dom_node.id + "_na_child_" + 
		now.valueOf() + "_" + new String(Math.random()).substr(2);
	    if (!__d.getElementById(id)) {
		// keep generating id until we have one that is unique
		break;
	    } else {
		this.caution("duplicate id generated, trying again...");
	    }
	}
	
	return id;
    }

    Blueprint.prototype._remove = function(req_id, id)
    {
	var i, n, e;

	this.debug("DESTRUCT " + id);

	try {
	    __star.removeInfotron(id, 1);

	this.postMessage("response_out", [req_id, "destruct", id]);
	} catch (e) {
	    this.error(e, "Error destructing " + id);
	}

	//	_onChildShutDown(id, []);
    }

    Blueprint.prototype._add = function(req_id, bp, iprops, xprops) 
    {
      var w, x, r, d, url;
	var qs = "";
	var now = new Date();
	var id = this._createUid();
	var na_props = {constructs_proactively:true};

	if (!bp) {
	    this.error("BP for construction not specified");

	    return;
	    /*****************************************************************/
	}

	for (key in iprops) {
	    qs += escape(key) + "=" + escape(iprops[key]) + "&";
	}

	if (typeof(bp) != typeof("")) {
	    bp = bp.toString();
	}

	if ((this._detect_uri && this._URI_REGEX.test(bp)) || this._bp_as_uri) {
	    url = bp;
	} else {
	    url = "";
	}

	d = __d.createElement("DIV");
	
	if (iprops) {
	    // this is not architectural, but it at overcomes some issues
	    // of the web, namely the case where we construct a web page
	    // that does NOT have a pasteboard at the top (i.e. non-JDA
	    // web page) which may never resize its window to fit the
	    // top level pasteboard
	    w = iprops["width"], h = iprops["height"];

	    if (!isNaN(w)) {
		d.style.width = w + "px";
	    }

	    if (!isNaN(h)) {
		d.style.height = h + "px";
	    }
	}

	if (xprops) {
	    // setting x,y,z on the container div takes advantage of
	    // DomRenderer's behavior which inherits these values
	    // when it deals with pasteboards contained within
	    // non-atomic infotrons
	    x = xprops["x"], y = xprops["y"], z = xprops["z"];

	    if (!isNaN(z)) {
		d.style.zIndex = z;
	    }
	    if (!isNaN(x)) {
		d.style.left = x + "px";
	    }
	    if (!isNaN(y)) {
		d.style.top = y +"px";
	    }
	    
	    if (xprops["_x_is_top_level"]) {
		na_props["uses_popup"] = true;
		// TODO: fix this architecturally
	        d.style.position = "absolute";
		d.style.zIndex = -10;
	    }
	}

	d.setAttribute("is_proxy", "true");
	d.id = id;
	d.innerHTML = "<a impl=\"" + bp + "\" href='" + url + ((qs) ? ("?" + qs) : "") + "'></a>";
	d.className = "non-atomic";

	this.dom_node.appendChild(d);

	// dynamically construct a non-atomic infotron
	// ( well, assume it's non-atomic, really )
	this._n ++;

	name = this._n + "_ready";
	__star.addIterm(this.id, name, 1);
	this.onMsg(name, "onReady");
	__star.connectTerminals([d.id, "%ready"], 
				[this.id, name]);

	name = this._n + "_error";
	__star.addIterm(this.id, name, 10);
	this.onMsg(name, "onError");
	__star.connectTerminals([d.id, "%error"], 
				[this.id, name]);

	name = this._n + "_shutdown";
	__star.addIterm(this.id, name, 1);
	this.onMsg(name, "onShutDown");
	__star.connectTerminals([d.id, "%shutdown"], 
				[this.id, name]);

	this._ids[id] = req_id;

	if (url) {
	  r = __star.addInfotron(id, this._NON_ATOMIC_BP, na_props);
	} else {
	  this.error("don't know the URL");
	}
    };

    Blueprint.prototype.onReady = function(msg)
    {
      this.debug(msg[0] + " CONSTRUCTED!");
      this.postMessage("response_out", [this._ids[msg[0]], "construct", msg[0], msg[1], msg[2]]);
    }

    Blueprint.prototype.onShutDown = function(msg)  
    {
       this.debug(msg + " SHUT DOWN!");
    }

    Blueprint.prototype.onError = function(msg)
    {
      this.error(msg[0] + "ERROR!");      
    }

    return Blueprint;
}, "NonAtomic Infotron Constructor");