Thursday, June 20, 2013

Metawidget. In. Spaaace.

Well, sort of.

Metawidget is now being used to power a (ground based) Global Navigation Satellite System called GALILEO, built by the European Union and European Space Agency.

I've written up a White Paper describing the project and Metawidget's role in it.

The team are using Metawidget's pluggable inspection architecture to enable them to reuse the detailed XML Schemas set up for transmission to/from the satellites, and generate a UI without having to respecify anything. They're also using Metawidget's pluggable widget processors to incorporate third-party validation libraries.

My thanks to the team for providing screenshots and details of their architecture!

More details here.

Friday, June 7, 2013

Node.js UI Generator: Metawidget v3.4

Version 3.4 of Metawidget, the Node.js UI generator is now available!

This release was focused on:
As always, the best place to start is the Reference Documentation:

http://metawidget.org/doc/reference/en/pdf/metawidget.pdf

Your continued feedback is invaluable to us. Please download it and let us know what you think.

Metawidget and Node.js

Inspired by a recent forum post and blog the next release of Metawidget (3.4) will be available as a Node.js module. This lets you use Metawidget to perform server side UI generation using JavaScript, if that's your requirement.

To install, simply use npm:

npm install metawidget

Then use the Metawidget API as normal:

var metawidget = require( 'metawidget' );
...
var mw = new metawidget.Metawidget( element );
mw.toInspect = {
   name: "Joe Bloggs",
   "DOB": "1/1/2001"
};
mw.buildWidgets();


// Print what was rendered

console.log( element.toString() );

This will render:

<table>
   <tbody>
      <tr id="table-name-row">
         <th id="table-name-label-cell"><label for="name" id="table-name-label">Name:</label></th>
         <td id="table-name-cell"><input type="text" id="name" name="name" value="Joe Bloggs"/></td>
         <td></td>
      </tr><tr id="table-DOB-row">
         <th id="table-DOB-label-cell"><label for="DOB" id="table-DOB-label">DOB:</label></th>
         <td id="table-DOB-cell"><input type="text" id="DOB" name="DOB" value="1/1/2001"/></td>
         <td></td>
      </tr>
   </tbody>
</table>

Which of course can be customized using Metawidget's pipeline architecture.

Metawidget must be used in combination with a DOM implementation. This can either be jsdom, envjs, or even a simple implementation of your own. For example:

var simpleDocument = {
   createElement: function( elementName ) {

      return {
         nodeType: 1,
         tagName: elementName.toUpperCase(),
         attributes: [],
         childNodes: [],
         setAttribute: function( name, value ) {

            for ( var loop = 0, length = this.attributes.length; loop < length; loop++ ) {
               if ( this.attributes[loop].nodeName === name ) {
                  this.attributes[loop].nodeValue = value;
                  return;
               }
            }

            this.attributes.push( {
               nodeName: name,
               nodeValue: value
            } );
         },
         hasAttribute: function( name ) {

            for ( var loop = 0, length = this.attributes.length; loop < length; loop++ ) {
               if ( this.attributes[loop].nodeName === name ) {
                  return true;
               }
            }

            return false;
         },
         getAttribute: function( name ) {

            for ( var loop = 0, length = this.attributes.length; loop < length; loop++ ) {
               if ( this.attributes[loop].nodeName === name ) {
                  return this.attributes[loop].nodeValue;
               }
            }

            return null;
         },
         appendChild: function( childNode ) {

            this.childNodes.push( childNode );
         },
         cloneNode: function() {

            var clone = simpleDocument.createElement( elementName );

            for ( var loop = 0, length = this.attributes.length; loop < length; loop++ ) {
               var attribute = this.attributes[loop];
               clone.setAttribute( attribute.nodeName, attribute.nodeValue );
            }
            for ( var loop = 0, length = this.childNodes.length; loop < length; loop++ ) {
               clone.appendChild( this.childNodes[loop].cloneNode() );
            }
            return clone;
         },
         removeChild: function( childNode ) {

            for ( var loop = 0, length = this.childNodes.length; loop < length; loop++ ) {
               if ( this.childNodes[loop] === childNode ) {
                  this.childNodes.splice( loop, 1 );
                  return childNode;
               }
            }

            throw new Error( "childNode not found: " + childNode );
         },
         ownerDocument: this,
         toString: function() {

            var toString = "<" + elementName;

            for ( var loop = 0, length = this.attributes.length; loop < length; loop++ ) {
               var attribute = this.attributes[loop];
               toString += ' ' + attribute.nodeName + '="' + attribute.nodeValue + '"';
            }

            if ( this.value !== undefined ) {
               toString += ' value="' + this.value + '"';
            }

            toString += ">";

            for ( var loop = 0, length = this.childNodes.length; loop < length; loop++ ) {
               toString += this.childNodes[loop].toString();
            }

            if ( this.innerHTML !== undefined ) {
               toString += this.innerHTML;
            }

            toString += "</" + elementName + ">";
            return toString;
         }
      };
   },
   createTextNode: function( data ) {

      return {
         nodeType: 3,
         toString: function() {

            return data;
         }
      }
   }
};

var element = simpleDocument.createElement( 'div' );

Metawidget must be wrapped around a DOM element. The Metawidget constructor takes this element, and thereafter always uses element.ownerDocument rather than referencing any global document object.