# Dojo 1.8 and AMD

### An overview with demos

Karsten Lehmann, Mindoo GmbH / @klehmann79

## About us

- IBM Business Partner and a Notes/Domino Design Partner
- Eclipse/Expeditor plug-ins and rich client applications
- XPages applications
- Web application development for IBM Websphere and Oracle Glassfish
- Karsten Lehmann and Tammo Riedinger
- Since 2004, developer of MindPlan for Haus Weilgut GmbH, mindmapping and project management for IBM Notes
- http://www.mindoo.de

## Goals

- Understanding concepts behind Dojo 1.8
- Reference book for new APIs
- Ideas and notes for individual experiments
- Tips for using Dojo in XPages in IBM Notes/Domino R9

## What is Dojo?

- Comprehensive, freely usable web toolkit
- APIs usable for Web and Mobile
- One toolkit: no clear separation in Web and Mobile
- Dojo 1.8 is part of IBM Notes/Domino R9!

## What is Dojo?

An SDK with four sections:

- dojo – general tools for JS development and Ajax
- dijit – UI components, e.g. layout and form elements
- dojox – additional UI components, including Mobile UI
- util – tools for build generation and unit tests

## Where do I find help?

- Dojo API documentation (link)
  comprehensive collection of tutorials, reference and API documentation
- Sitepen blog (link)
- Final solution:
  Dojo source code – everything is open source!

## Dojo releases

- July 2010 - Dojo 1.5
- March 2011 - Dojo 1.6
- October 2011 - Lotus Notes 8.5.3 with Dojo 1.6
- December 2011 - Dojo 1.7
- August 2012 - Dojo 1.8
- March 2013 - IBM Notes 9.0 with Dojo 1.8
- May 2013 - Dojo 1.9
- ? - Dojo 2.0 (roadmap discussion)

## Differentiation between jQuery, Dojo, extJS

ExtJS / Sencha Touch

- Strong separation between data and presentation
- Mixed license: open source and commercial
- Many commercial components available
- Support by manufacturer Sencha

## jQuery

- Largest developer community
- Visually highly appealing jQuery plug-ins
- Syntax requires getting used to
- Little abstraction from browser DOM

## Dojo

- Comprehensive toolkit for Web and Mobile
- Few extensions / additional components on the net
- Can be visually enhanced with jQuery
- First class citizen in XPages, part of the framework

## New in Dojo 1.8 - Web

dojox/calendar (demo)

(has scalability issues)

## New in Dojo 1.8 - Web

dojox/dgauges (demo)

## New in Dojo 1.8 - Web

dojox/treemap (demo)

## New in Dojo 1.8 - Mobile

28 new widgets:
selection dialogs, progress bars, audio/video, scrolling areas inside pages, badge icons (demo)

## New in Dojo 1.8

- First components without support for Firefox 3.6 and IE6
- XPages in the Notes Client R9 still based on the Firefox 3.6 engine!

## New since Dojo 1.6 (Notes 8.5.3)

- Even more widgets
- Web: among others dgrid – flexible table component
- Mobile: 21 new widgets
  e.g. Pop-up dialogs (opener, tooltip), ComboBox, SpinWheel
- Additional information: link

## New since Dojo 1.6 (Notes 8.5.3)

- AMD: Asynchronous Module Definition
- Loads Dojo classes and individual code, replaces dojo.require()
- Many APIs renamed and reorganized for 2.0,
  old APIs still usable though
- Considerably smaller Dojo core, loading additional modules on demand

## Maqetta

- Free WYSIWYG editor for Dojo applications
- Web and Mobile
- Available for download or to be used in the cloud (link)

## Create web layouts –
declarative approach

## Create web layouts –
declarative approach

- Layout in the form of HTML tags
- Width and shape adjustable via CSS style
- Variety of layout containers that can
  be nested available
- Used mainly for static contents

## dojox/layout/BorderContainer

- Well suited as basic layout
- Five areas: top, left, right, bottom and center
- Only center has to be filled
- Several widgets per area through `layoutPriority` attribute (defines sequence)

## BorderContainer

design="headline", two widgets for "right" here

## BorderContainer

The same layout with design="sidebar":

## BorderContainer

    <!DOCTYPE html>
    <html>
    <head>
    <script type="text/javascript"
      src="/xsp/.ibmxspres/dojoroot-1.8.0-u/dojo/dojo.js"
      data-dojo-config="parseOnLoad:true"></script>
    <link rel="stylesheet" type="text/css"
      href="/xsp/.ibmxspres/dojoroot-1.8.0-u/dijit/themes/claro/claro.css">
    <link rel="stylesheet" type="text/css"
      href="/xsp/.ibmxspres/dojoroot-1.8.0-u/dojo/resources/dojo.css">
    <style>
    html,body {
      width:100%;height:100%;margin:0;overflow:hidden;
    }
    </style>
    <script type="text/javascript">
      <!-- load required widgets -->
        require( ['dijit/layout/BorderContainer',
        'dijit/layout/ContentPane'],
          function(BorderContainer, ContentPane) {
          }
        );
    </script>
    </head>
    <body class="claro">
    <!-- BorderContainer -->
    <div id="mainContainer" data-dojo-type="dijit/layout/BorderContainer"
      style="width:100%;height:100%">

      <!-- contained ContentPanes -->
      <div id="topPane" data-dojo-type="dijit/layout/ContentPane"
        data-dojo-props="region:'top'" style="height:30px">
          Top pane
      </div>

      <div id="leftPane" data-dojo-type="dijit/layout/ContentPane"
        data-dojo-props="region:'left',splitter:true" style="width:20%">
          Left pane
      </div>

      <div id="centerPane" data-dojo-type="dijit/layout/ContentPane"
        data-dojo-props="region:'center'">
          center pane
      </div>

      <div id="rightPane1" data-dojo-type="dijit/layout/ContentPane"
        data-dojo-props="region:'right',layoutPriority:1" style="width: 10%">
          1st right pane from right
      </div>

      <div id="rightPane2" data-dojo-type="dijit/layout/ContentPane"
        data-dojo-props="region:'right',layoutPriority:2" style="width: 10%">
          2nd right pane from right
      </div>

      <div id="bottomPane" data-dojo-type="dijit/layout/ContentPane"
        data-dojo-props="region:'bottom'">
          first bottom pane
      </div>

    </div>
    </body>
    </html>

## data-dojo-* attributes

- HTML5 conform attribute names
- `data-dojo-config`
  central Dojo configuration

    <script type="text/javascript"
      src="/xsp/.ibmxspres/dojoroot-1.8.0-u/dojo/dojo.js"
      data-dojo-config="parseOnLoad:true"></script>

Global variable alternative:

    <script type="text/javascript">
    dojoConfig={
      parseOnLoad: true
    }
    </script>
    <script type="text/javascript" src="/path/to/dojo.js"></script>

## data-dojo-* attributes

- `data-dojo-type`
  Class name of widget (separator " / " or " . ")
- `data-dojo-props` (optional)
  Widget properties (cf. API documentation)

    <div id="topPane" data-dojo-type="dijit/layout/ContentPane"
      data-dojo-props="region:'top'" style="height:30px">
        Top pane
    </div>

## require

- AMD command for loading classes
- Blocking or asynchronous depending on the mode
- Calls up callback as soon as classes are available
- Necessary for tags to become widgets

    <script type="text/javascript">
      <!-- load required widgets -->
        require( ['dijit/layout/BorderContainer',
          'dijit/layout/ContentPane'],
            function(BorderContainer, ContentPane) {
              //Callback with access to load classes
            }
        );
    </script>

## Dojo Parser

- Parser can also be called manually
- parseOnLoad: false
- Advantage:
  Callback call as soon as widgets are generated

    <script type="text/javascript">
      require( ['dijit/layout/BorderContainer', 'dijit/layout/ContentPane',
        'dojo/parser', 'dojo/ready'],
        function(BorderContainer, ContentPane, parser, ready) {
          //dojo/ready waits for DOM to load
          ready(function() {
            parser.parse().then(function(arrWidgets) {
              //called with array of all created widgets
                for (var i=0; i<arrWidgets.length; i++) {
                  console.log('Widget created: '+arrWidgets[i].id);
                }
            });
          });
      });
    </script>

## Other layout widgets

- `dijit/layout/ContentPane`
  Container for random DOM nodes
- `dijit/layout/AccordionPane`Several areas below each other, one visible
- `dijit/layout/TabContainer`Tab
- `dojox/layout/ExpandoPane`
  Closable sidebar
- `dojox/layout/GridContainer`
  Portal layout

## Portal layout

Portal with two portlets

    <!DOCTYPE html>
    <html>
    <head>
    <script type="text/javascript"
        src="/xsp/.ibmxspres/dojoroot-1.8.0-u/dojo/dojo.js"></script>
    <link rel="stylesheet" type="text/css"
        href="/xsp/.ibmxspres/dojoroot-1.8.0-u/dijit/themes/soria/soria.css">
    <link rel="stylesheet" type="text/css"
        href="/xsp/.ibmxspres/dojoroot-1.8.0-u/dojo/resources/dojo.css">
    <link rel="stylesheet" type="text/css"
        href="/xsp/.ibmxspres/dojoroot-1.8.0-u/dojox/widget/Portlet/Portlet.css">
    <link rel="stylesheet" type="text/css"
        href="/xsp/.ibmxspres/dojoroot-1.8.0-u/dojox/layout/resources/GridContainer.css">
    <style>
    html,body {width:100%;height:100%;margin:0;overflow:hidden}
    .gridContainerTable {border:0;height:inherit}
    .gridContainer > div {height:inherit}
    </style>
    <script type="text/javascript">
        require( ['dijit/layout/BorderContainer',
        'dijit/layout/ContentPane', 'dojox/layout/GridContainer',
        'dojo/parser', 'dojo/ready',
        'dojox/widget/Portlet'],

        function(BorderContainer, ContentPane, GridContainer, parser,
        ready, Portlet) {
            ready(function() {
                parser.parse();
            });
        });
    </script>
    </head>
    <body class="soria">
    <div id="mainContainer" data-dojo-type="dijit/layout/BorderContainer"
      data-dojo-props="design:'sidebar'" style="width: 100%; height: 100%">

    <!-- Portal visible in center area -->
    <div id="portal" data-dojo-type="dojox/layout/GridContainer"
      style="height:100%" data-dojo-props="nbZones:3,region:'center',
      hasResizableColumns:true,isAutoOrganized:false,withHandles:true,
      dragHandleClass:'dijitTitlePaneTitle',colWidths:[20,60,20]">

      <!-- First portlet -->
      <div id="portlet1" data-dojo-type="dojox/widget/Portlet"
      data-dojo-props="title:'Portlet 1',column:1">
        Hello World.
      </div>

      <!-- Second portlet -->
      <div id="portlet2" data-dojo-type="dojox/widget/Portlet"
      data-dojo-props="title:'Portlet 2',closable:false,column:2">
        Greetings from Entwicklercamp.
      </div>
    </div>
    </body>
    </html>

## Portal layout

3 columns, portlets movable via drag and drop

## Demo: portal layout

## Generating widgets in JavaScript

- Widget generation in JavaScript
- Very flexible in interaction with Ajax
- Dojo widgets form a tree structure:

    require(['dijit/registry', 'dijit/layout/ContentPane'],
      function(registry, ContentPane) {

      //add widgets via addChild()
      //main: existing dijit/layout/BorderContainer
      var mainContainer=registry.byId('main');
      var newPanel=new ContentPane({
        id: 'contentpane1',
        content: 'Pretty dynamic content '+(new Date()).toString(),
        region:'bottom',
        splitter: true
      });
      mainContainer.addChild(newPanel);
      //resize recalculates positions
      mainContainer.resize();

      //read contained widgets via getChildren()
      var arrChildren=mainContainer.getChildren();

      //remove widgets via removeChild()
      var childWidget=arrChildren[0];
      mainContainer.removeChild(childWidget);
      //if no longer needed, free up all resources
      childWidget.destroyRecursive();
    }

## Demo: dynamic UI

## Form widgets

Widgets can be placed freely, either declarative:

    <body>
    Lorem ipsum dolor sit amet.<br />
    <input type="text" data-dojo-type="dijit/form/TextBox" /><br />
    consetetur sadipscing elitr.
    </body>

## Form widgets

...or programmatic:

    require(['dojo/_base/window', 'dojo/dom', 'dijit/registry'],
      function(win, dom, registry) {
        //get target DOM node with ID 'targetDomNodeId':
        var targetDomNode=dom.byId('targetDomNodeId');
        //get existing widget with ID 'myWidgetId':
        var myWidget=registry.byId('myWidgetId');
        //Change widget position
        //(first/last=first/last child,
        //before/after=before/after reference node)
        myWidget.placeAt(targetDomNode, 'first');
      }
    });

## Demo: form widgets overview

link

## A collection of important APIs:

(Please learn all of them by heart! ;-) )

## Important widget APIs

Widget can be located via its ID

    // dijit/registry
    var widget=registry.byId('widgetId1');

Reading/writing of properties

    var propValue=myWidget.get('value')
    myWidget.set('value', 'xyz');

## Important DOM APIs

DOM node can be located via its ID

    // dojo/dom
    var nodeWithId=dom.byId('nodeId1')

Reading and changing styles

    // dojo/dom-style
    var styleValue=domStyle.get(node, 'display');
    domStyle.set(node, 'backgroundColor', '#ff0000');

## Important DOM APIs

Reading/writing DOM node classes

    // dojo/dom-class
    var nodeHasClass=domClass.has(node, 'myclass');
    domClass.add(node, 'myclass');
    domClass.remove(node, 'myclass');

Generating and placing DOM nodes

    // dojo/dom-construct
    domConstruct.empty(refNode);
    var createdNode=domConstruct.create('div',
      {innerHTML:'<b>Test</b>'}, refNode, 'first');
    domConstruct.place(refNode, otherNode, 'before');

Dimensions of DOM node

    // dojo/dom-geometry
    var box=domGeom.getMarginBox(node);
    //box.width, box.height, box.top, box.left

## Important DOM APIs

Finding DOM nodes via CSS Selector

    // dojo/query
    var arrNodes = query('.headline', bodyNode);

## Wichtige Dojo-APIs

Language-dependant date formatting

    // dojo/date/locale
    var formattedDateStr=locale.format(myDate, {selector:'date'});

Conversion between date and ISO8601 format

    // dojo/date/stamp
    var parsedDate=stamp.fromISOString(isoDateStr);
    var dateAsString=stamp.toISOString(mydate);

Searching a value in arrays

    // dojo/_base/array
    var index=array.indexOf(myArray, valueToFind);

## Important Dojo APIs

Parsing JSON strings and formatting objects as JSON

    // dojo/json
    var parsedJsonObj=JSON.parse("{'foo':'bar'}");
    var jsonStr=JSON.stringify( {foo:'bar'} );

…and finally:

    // dojo/_base/lang
    // clone object recursively
    var clonedObj=lang.clone(obj);

    // run code in different scope
    var myfunction=lang.hitch(mygrid,
      function(key, value) {this.set(key, value);} );
    myfunction('store', newStore);

    // check for data type:
    lang.isArray(x) / lang.isFunction(x) / lang.isObject(x) /
    lang.isString(x)

    // replacing text
    lang.replace("Hello {name.first} {name.last}!",
      { name: {first:  "Rudi", last: "Knegt"} });

## Registering events

Reacting to events

## The new dojo/connect

dojo.connect was divided:

- dojo/on - DOM events
- dojo/aspect - hooks for class methods

## dojo/on

"on" in the event name is cut out:

    //Register event code for onClick event:
    //uses dojo/dom and dojo/on
    var myDomNode=dom.byId('nodeId');
    var signal=on(myDomNode, 'click',
      function(evt) {alert('Node clicked'); });

    //unregister event code:
    signal.remove();

## Event delegation

Intercepting 'bubbling’ events in parent containers

    <div id="parentDiv">
      <button id="button1" class="clickMe">Click me</button>
      <button id="button2" class="clickMe">Click me also</button>
      <button id="button3" class="clickMe">Click me too</button>
      <button id="button4" class="clickMe">Please click me</button>
    </div>
    <script>
    require(["dojo/on", "dojo/dom", "dojo/domReady!"],
      function(on, dom, domReady) {

        var myObject = {
          id: "myObject",
          onClick: function(evt){
            alert("The scope of this handler is " + this.id);
          }
        };
        var div = dom.byId("parentDiv");
        on(div, ".clickMe:click", myObject.onClick);
      });
    </script>

## dojo/aspect

- Aspect-oriented programming
- aspect.before, aspect.after and aspect.around

    require(['dojo/aspect', 'dojo/json', 'dojo'],
      function(aspect, JSON, dojo) {

      //overwrite old method 'dojo.xhrGet()'
      aspect.around(dojo, "xhrGet", function(originalXhr) {
        return function(args) {
          var t0=new Date().getTime();

          //call original method
          var deferred = originalXhr(args);

          //we add a callback to the deferred object
          deferred.then(function(data) {
            var t1=new Date().getTime();
            console.log("Data read in "+(t1-t0)+
              "ms with request: "+JSON.stringify(args));
          });

          //and forward it to the caller
          return deferred;
        }
      });
    });

## dojo/topic

- Publish/subscribe architecture
- Decouples message sender from recipient
- used for drag and drop system:
  /dnd/start, /dnd/cancel, /dnd/drop

    require(['dojo/topic'], function(topic) {
      topic.subscribe("some/topic", function(event){
        // process object 'event'
      });
      //publish new event object to all subscribers
      topic.publish("some/topic", {name:"My Birthday Party",
        location:"Karlsruhe"});
    });

## Working with data

Web forms and Ajax

## Dojo forms

- `dijit/form/Form` simplifies working with web forms
- Reading and writing form data as a JS object
- Validating the form with `myform.validate()`

## Dojo forms

`dijit/form/Form` becomes FORM tag in DOM:

    <div id="myformid" data-dojo-type="dijit/form/Form">
      <table>
        <tr>
          <td>Firstname</td>
          <td><input type="text" name="firstname"
            data-dojo-type="dijit/form/TextBox" /></td>
        </tr>
        <tr>
          <td>Lastname</td>
          <td><input type="text" name="lastname"
            data-dojo-type="dijit/form/TextBox" /></td>
        </tr>
      </table>
    </div>

## Dojo forms

Form data can be extracted and set:

    require(['dojo/json', 'dijit/registry'],
      function(JSON, registry) {
        var myform=registry.byId('myformid');
        var formData=myform.get('value');

        //show form data as JSON string:
        alert(JSON.stringify(formData));

        //update form fields based on
        //"name" attribute of fields
        myform.set('value', {firstname:'Rudi', lastname:'Knegt'});

        //validate form
        if (!myform.validate())
          alert('Form content invalid!');
      }
    });

## Demo: reading/writing form data

## Ajax requests

## dojo/request/xhr

- Replaces dojo.xhrGet() / .xhrPost()
- xhr package also comprises cross domain protocols like IFrame/JSONP

    require(["dojo/request/xhr"], function(xhr) {
      xhr("myxagent.xsp", {
        handleAs: "json"
        method: "GET"
      }).then(function(data) {
            //process data (here JS object of JSON data)
          }, function(err) {
            //report/log error
          }, function(evt){
            //process progress info
            //(requires browser support for XHR2)
          });
    });

## Demo: Notes views with LazyTreeGrid

## AMD

Asynchronous Module Definition

## AMD

- Class loader for Dojo classes and individual code
- Experimental in Dojo 1.6, standard since 1.7
- New asynchronous mode generates script tags instead of xhr
- Better performance in browser than with xhr
- New API distribution leads to smaller code units
- More compact custom builds, but also more HTTP requests without optimization

## More HTTP requests?

Surely, it can’t be that many!

## That was our grid example :-)

## Solutions

- Custom builds (tutorial)
- XPages runtime optimizer:
  "Use runtime optimized JavaScript and CSS resources"
- Combines Dojo classes and dependencies

## Asynchronous class loading

Activation with data-dojo-config

    <script type="text/javascript" src="path/to/dojo.js"
      data-dojo-config="async:true"></script>

- `async:false (Default)`
  Loading of Legacy APIs, e.g. dojo.connect, dojo.xhrGet etc.
- `async:true`
  Loading only dojo nano kernel (small)
- With XPages in R9, unfortunately always `async:false`

## Legacy APIs

With async:true, legacy APIs can be loaded as "dojo" module:

    require(['dojo'], function(dojo) {
      dojo.connect(...);
    });

## define

Defining individual AMD modules

## define

Syntax analogous to require:

- Integrating dependencies
- Callback function called after loading process
- The difference: We give something in return!

    //Content of "/subdir/db.nsf/dojo/mindoo/tools/XspUtil.js":

    define(['dojo/query'], function(query) {
      //return simple JS object with one method
      return {
        //getClientId finds DOM nodes with ID ending with sComponentId
        getClientId: function(sComponentId) {
          var arrNodes=query("[id$='"+sComponentId+"']");
          if (arrNodes && arrNodes.length>0) {
            var sId=arrNodes[0].id;
            return sId;
          }
       }
      }
    });

## require

Using the defined module:

- Define the package location
- Load modules/classes

    <script type="text/javascript">
    dojoConfig={
      packages:[
        { name:'mindoo', location:'/subdir/db.nsf/dojo/mindoo' }
      ]
    }
    </script>
    <script type="text/javascript" src="path/to/dojo.js"></script>
    <script type="text/javascript">
      //use classname of new module in require call:
      require(['mindoo/tools/XspUtil', 'dojo/domReady!'],
        function(XspUtil, domReady) {
          //call new defined method:
          var clientId=XspUtil.getClientId('mytextfield');
          alert(clientId); // view:_id1:mytextfield
      });
    </script>

## define for advanced users

Inheritance of classes with define:

    define(['dojo/_base/declare', 'dojox/data/QueryReadStore'],
      function(declare, QueryReadStore) {
        //create class "mindoo/data/QueryReadStoreExt" as subclass
        //of "dojox/data/QueryReadStore"
        //optional 1st parameter with classname in declare() call,
        //becomes global variable:
        return declare("mindoo/data/QueryReadStoreExt", [QueryReadStore], {

           fetch:function(request) {
             request.serverQuery = {q:request.query.name};

             //call superclass method:
             return this.inherited("fetch", arguments);
           }
        });
    });

The result can be loaded via require and instantiated with new.

## Loading files

- AMD special module "module" delivers path to current class
- AMD plugin "dojo/text" loads files via Ajax

    require(['module', 'dojo/dom'],
      function(module, dom) {
        var moduleUri=module.uri;

         //compute template path
         var templatePath=moduleUri+"/../templates/mytemplate.html";

         //load HTML file
         require(['dojo/text!' + templatePath], function(template) {
            dom.byId('content').innerHTML = template;
         });
    });

Parsing of template and value replacement e.g. with
Django template language dojox/dtl

## Now there is potential!

Demo: Activity stream in NSF

## Integration in XPages

## Using widgets

Activating Dojo option "parseOnLoad" with the Dojo panel of the XPage:

## Using widgets

Entering required Dojo classes in the resource tab:

Notation with " . " in R9 Beta is required here to be able to use JS Optimizer

## Using widgets

- Equipping tags with Dojo type and attributes
- For layout widgets either with xp:div or xp:panel

## Using widgets

Analog approach for fields:

## Using individual classes

Defining package location with
"Resources / Add / Dojo Module Path Resource",
then adding class as "Dojo module"

## Using individual classes

Location of Dojo file in DB Design (package explorer)

## Partial-refresh-resistant surfaces

- Partial refresh sends field contents to the server that recalculates the page area
- Returned HTML is injected into the page and parsed for Dojo widgets mark-up
- May lead to a reset of widget properties:
  active tabs, scroll position in BorderContainer etc.
- Solution: using partial refresh selectively or not at all

## Finally readable Dojo sources!

- New feature in Notes/Domino R9:
  "Use uncompressed resource files (CSS & Dojo)"
- Worth a mint for the debugging of problems

# Thank you!

### Time for questions!

## Resources

Dojo is great because:

- 10 Reasons Why Your Projects Should Use the Dojo Toolkit

Dojo features

- Differences between 1.6 and 1.7
- What's coming in Dojo 1.8 | The Dojo Toolkit Blog
- Dojo 1.8 Release Notes — The Dojo Toolkit - Reference Guide
- Calendar Sample: Desktop
- Learning Dojo 1.8 | Blog | SitePen

## Resources

Dojo features

- API Documentation - The Dojo Toolkit
- assonos blog : dojo article series and presentation

Dojo Mobile 1.7 and 1.8

- Dojo Mobile Showcase
- Get started with Dojo Mobile 1.7
- Dojo Mobile 1.7 New Widgets
- Dojo Mobile 1.8 Work-In-Progress
- What's new in Dojo Mobile 1.8, Part 1
- What's new in Dojo Mobile 1.8, Part 2
- What's new in Dojo Mobile 1.8, Part 3

## Resources

Dojo 2.0

- Dojo 2.0: Modular, Mobile, and Reinventing Web App Development

Layouts

- Dijit layout — The Dojo Toolkit - Reference Guide
- DojoX Portlet In a GridContainer example
- Layout with Dijit - The Dojo Toolkit

Dojo forms

- Forms and Validation - The Dojo Toolkit
- dojo dijit.form.DateTextBox constraints

## Resources

Event handling

- Events with Dojo - The Dojo Toolkit
- Using dojo/aspect
- Keyboard Events with Dojo - The Dojo Toolkit

Drag and Drop

- Dojo Drag'n'Drop Redux | Blog | SitePen

AMD

- Learn more about AMD! | The Dojo Toolkit Blog
- The Dojo Loader — The Dojo Toolkit - Reference Guide
- Defining Modules - The Dojo Toolkit
- Differences between CommonJS wrapper and AMD define

## Resources

AMD

- dojo/domReady! — The Dojo Toolkit - Reference Guide
- dojo/text — The Dojo Toolkit - Reference Guide

Special effects

- Gruppler's Effect Demos
- Textillate.js
- Parallax Scrolling
- Scrollorama

Mobile Scrollpane

- iScroll 4

## Resources

Alternative UI components

- Create a Clearable TextBox with the Dojo Toolkit
- Demos - JavaScript InfoVis Toolkit
- Icicle - Icicle Tree with static JSON data
- Icicle - Icicle tree with limited levels shown
- Fixed Icicle request loading - philogb/jit - GitHub
- Highcharts

Custom Builds

- Creating Builds - The Dojo Toolkit

## Resources

Miscellaneous

- ensure - Ensures relevant script and html are loaded
- Wink toolkit - A mobile JavaScript framework
- 10 Great Google Font Combinations You Can Copy
- Findings
- CoolCarousels - Showcasing 64 cool jQuery carousel examples