Javascript Packaging Specification

The Javascript packaging specification aims to define as little as possible, allow for future extension of the spec, and to promote the complete decentralization of parts while leaving the Javascript language specification untouched.

BLUEPRINT

The blueprint of each javascript part is packaged by using a function known as BLUEPRINT.

BLUEPRINT(
);

Each Javascript file can contain zero or more packaged javascripts.

Having a single packaged javascript in a given javascript file can make it easier for others to use your part. However, for performance reasons, it is recommended that you bundle up all packaged javascripts into one big file to minimize overhead.

UUID

Each packaged Javascript must have a UUID to enable decentralized identification and management. Most Web resources are identified by a URL. A URL is a location-specific identifier, while a UUID is not. The following example shows how you can declare the UUID of of a given Javascript part.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
);

A UUID can be generated with tools such as this. We recommend that you remove the hyphens, as they are not actually part of the UUID. For convenience, you can simply download a blank Javascript part from our Website. Each new download will have a new UUID.

Name

Each packaged javascript must have a name. The following is an example of how you declare the name of a given javascript part.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  }
);

Instead of considering each Javascript part as a verb as one would commonly do when naming functions, please consider it as an entity that does something with the information coming in. Quite often javascript parts have names that are found in the real world. Countdown Timer, for example, is exactly such an example.

Inputs

Each packaged javascript can specify zero or more inputs. The following is an example of how you specify a single input.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"]
  }
);

The following is an example of how you declare two inputs.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"
              ,"stop_trigger_in"]
  }
);

Each input is separated with a comma.

There is also a special input known as __power__. By declaring this input, you express an interest in knowing when the part is powered and ready to start. As soon as it is, the time stamp of that moment is sent through this input. If this input is connected to an internal function, the function will be passed this time as a parameter. The following is an example of how you would declare this special input in addition to the two inputs previously defined.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"
              ,"stop_trigger_in"
	      ,"__power__"]
  }
);

To make the lives of those who use your part more pleasant, please be conscious of how you name your inputs. For example, let's look at start_trigger_in. Messages coming through this input could have been anything in its previous context, but in the context of this part it is a start_trigger. I may then notice the stop_trigger_in input, and understan that there are two different kinds of triggers: one starts, and the other stops. Be as clear as possible about the meaning of the message coming through a given input.

Input Specs

Each packaged javascript can specify extra details for each of its input. The following is an example of how you specify the queue size of the first input.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"
              ,"stop_trigger_in"
	      ,"__power__"]
  , "input_specs": [{"queue_size": 10
	            }
	           ]
  }
);

The following is an example of how you specify the queue size of both the first and the second output.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"
              ,"stop_trigger_in"
	      ,"__power__"]
  , "input_specs": [{"queue_size": 10
	            }
	           ,{"queue_size": 10
                    }
		   ]
  }
);

The following is an example of how you specify the queue size of the second output, but not the first.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"
              ,"stop_trigger_in"
	      ,"__power__"]
  , "input_specs": [{
	            }
	           ,{"queue_size": 10
                    }
		   ]
  }
);

Please note that the sequence of the input specs map directly to the inputs.

Outputs

Each packaged javascript can specify zero or more output. The following is an example of how you specify a single output.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"
              ,"stop_trigger_in"
	      ,"__power__"]
  , "input_specs": [{
	            }
	           ,{"queue_size": 10
                    }
		   ]
  , "outputs": ["time_reached_indication_out"]
  }
);

You can use the same technique as you did with the inputs to specify two or more outputs.

To make the lives of those who use your part more pleasant, please be conscious of how you name your outputs. For example, let's look at time_reached_indication_out. Messages coming through this output is an indication of time having been reached. Be as clear as possible about the meaning of the message coming through a given input.

Properties

Each Constructible HTML file can specify zero or more avaialble properties. The following is an example of how you specify the availability of a single property.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"
              ,"stop_trigger_in"
	      ,"__power__"]
  , "input_specs": [{
	            }
	           ,{"queue_size": 10
                    }
		   ]
  , "outputs": ["time_reached_indication_out"]
  , "properties": ["does_trigger_automatically"
                  ]
  }
);
	  

The following is an example of how you specify the availability of two properties.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"
              ,"stop_trigger_in"
	      ,"__power__"]
  , "input_specs": [{
	            }
	           ,{"queue_size": 10
                    }
		   ]
  , "outputs": ["time_reached_indication_out"]
  , "properties": ["does_trigger_automatically"
                  ,"triggers_in_milliseconds"
                  ]
  }
);

Each property name is separated with a comma.

To make the lives of those who use your part more pleasant, please be conscious of how you name your properties. Here are some rules of thumb that we have come up with. (If you believe there are better ones, please let us know.)

Implementation

The logic of the packaged javascript is defined inside a function block, as shown below.

BLUEPRINT ( 
  "1ab7ddeea4bd428996c746cea52fae82"
, { "name": "Countdown Timer"
  , "inputs": ["start_trigger_in"
              ,"stop_trigger_in"
	      ,"__power__"]
  , "input_specs": [{
	            }
	           ,{"queue_size": 10
                    }
		   ]
  , "outputs": ["time_reached_indication_out"]
  , "properties": ["does_trigger_automatically"
                  ,"triggers_in_milliseconds"
                  ]
  }
, function(Class) {

}
);

Initialization

The _onInit_ method is called when your part is loaded. The properties set on the part is passed in as the only parameter. The following is an example from the Countdown Timer.

, function(Class) {
	      
  Class.prototype._onInit = function(props) {
	this._timeout = props["triggers_in_milliseconds"] || 1000;
	this._auto = props["does_trigger_automatically"];
	this._use_ltime = props["does_use_local_time"];
  };

}

When it comes to properties whose value can be either true or false, we recommend that you choose one that is false unless specified true. In the above example, if you believe the typical behavior ought to be to trigger automatically, rename the property to does_trigger_manually. This prevents the need to specify any property to try the part out in its most typical manner.

You should not post messages during initialization, because there is no guarantee that the parts have all been assembled yet. In other words, the message you post at this point may not reach any othe part.

Message Handling

If you want to post messages as soon as possible, do it when you receive a message through your __power__ input. The following is an example of how the Countdown Timer handles messages.

, function(Class) {

  Class.prototype._onInit = function(props) {
	this._timeout = props["triggers_in_milliseconds"] || 1000;
	this._auto = props["does_trigger_automatically"];
	this._use_ltime = props["does_use_local_time"];
  };

  Class.prototype.onMsgFor["__power__"] = function(msg)  {
	if (this._auto) {
	    this.onMsgFor["start_trigger_in"].call(this, msg);
	}
  };

  Class.prototype.onMsgFor["start_trigger_in"] = function(msg) {
	var self = this;
	
	function __func()
	{
	    self.onTimeout();
	};
	
	this.onMsgFor["stop_trigger_in"].call(this);
	this._id = window.setTimeout(__func, this._timeout);
  };

  Class.prototype.onMsgFor["stop_trigger_in"] = function(msg) {
	if (this._id) {
	    window.clearTimeout(this._id);
	}
  };
    
  Class.prototype.onTimeout = function() {
	var t, d = new Date();

	if (!this._use_ltime) {
	    t = {"year" : d.getUTCFullYear(),
		 "month": d.getUTCMonth(),
		 "day": d.getUTCDate(),
		 "hour": d.getUTCHours(),
		 "minute": d.getUTCMinutes(),
		 "second" : d.getUTCSeconds(),
		 "miliseconds" : d.getUTCMilliseconds()};
	} else {
	    t = {"year" : d.getFullYear(),
		 "month": d.getMonth(),
		 "day": d.getDate(),
		 "hour": d.getHours(),
		 "minute": d.getMinutes(),
		 "second" : d.getSeconds(),
		 "miliseconds" : d.getMilliseconds()}
	}
	
	this.postMessage("time_reached_indication_out", t);
  };

}

For the specification of the programming interface, please review this document.

For the specification on how to use and assemble parts together in a Constructible HTML, please review this document.

Please browse the catalog for complete examples.

Questions about the spec? Tell us about it below!

Download