never bet against the open web
DESCRIPTION
Never Bet Against The Open Web - Rich Web Experience 2011TRANSCRIPT
© SitePen, Inc. All Rights Reserved
Never Bet Against the Open Web
presents
© SitePen, Inc. All Rights Reserved
Nice to Meet you
Co-Founder of Dojo Toolkit
CEO, SitePen, Inc.
President, Dojo Foundation
Dylan Schiemann
@dylans @sitepen @dojo
© SitePen, Inc. All Rights Reserved
This talk was very different just six months ago.
© SitePen, Inc. All Rights Reserved
IE6, Flash and Silverlight Liberation Movement
© SitePen, Inc. All Rights Reserved
"Flash to Focus on PC Browsing and Mobile Apps; Adobe to More Aggressively
Contribute to HTML5"
- Danny Winokur, VP & GM, Interactive Development at Adobe
© SitePen, Inc. All Rights Reserved
"Silverlight is %&#ing dead... most of the team have been split apart and others have
left the company altogether."
- Scott Barnes, former Rich Platforms Product Manager at Microsoft for the Silverlight team
© SitePen, Inc. All Rights Reserved
"Technologies that lock things down tend to lose in the end. People want freedom
and markets want freedom."
- Linus Torvalds, talking about App Stores and Windows 8 Secure Install
© SitePen, Inc. All Rights Reserved
"SUN has lost a huge opportunity while not leveraging JWebPane"
- Dominique De Vito
© SitePen, Inc. All Rights Reserved
"Project Avatar: One HTML5 Strategy to Rule Them All... unifying ME and EE means agreeing on JSON
as a communication mechanism for passing objects back and forth. And it also means
leveraging Web Sockets"
- TheServerSide.com
© SitePen, Inc. All Rights Reserved
"IE 6 and 7: A Plague Upon Us That Must Die a Bloody Death
Chrome Frame: aka the IE Antivirus or Tapeworm"
-Me, 2009
© SitePen, Inc. All Rights Reserved
Where did Flash/Flex and Silverlight Fail?
They tried to replace the web, rather than improving it.
Apple said no.
Developers said no.
HTML5 tsunami.
Chrome and Firefox rate of updates.
Adobe and Microsoft started listening.
Major enterprises contribute
IBM, AOL to Dojo
Adobe, Microsoft to jQuery
© SitePen, Inc. All Rights Reserved
Browser Economics: Standards
0% 25% 50% 75% 90% 100%
Cos
t*
Standards Compliance*Cost is an artificial number factoring in R&D and opportunity costs
© SitePen, Inc. All Rights Reserved
Key Open Web Components
Tools you need to build great apps and user experiences
Simplicity: content, fast and efficient, easy to parse, hyperlinks, style, standard, easy to distribute
HTTP(S), TCP/IP
HTML(5), CSS(3), JavaScript
Vector graphics (Canvas and SVG)
WebSockets/Comet, Local Storage/Offline, Data/IndexedDB, WebGL, Audio/Video, etc.
© SitePen, Inc. All Rights Reserved
Evolution of Web App Development
https://secure.flickr.com/photos/bytemarks/4733371072/sizes/l/in/photostream/
© SitePen, Inc. All Rights Reserved
Evolution of Web App Development
https://secure.flickr.com/photos/dylans/3439037456/
Web 1.0
Dumb client, smart server
Focus on HTML & CSS, "separation of markup and presentation"
© SitePen, Inc. All Rights Reserved
Evolution of Web App Development
Web 2.0
Smarter client, smart server, con$ict
Initial break of many paradigms
Search indexing, history, navigation
Didn't really account for mobile
DOM-centric
Ajax: sort of real-time
© SitePen, Inc. All Rights Reserved
https://secure.flickr.com/photos/dylans/5206483166/
We Want More
© SitePen, Inc. All Rights Reserved
Revolution: Separation of Data and UX
Users want access to data, info
in a variety of experiences
relevant to their current context
Aggregation
User Interfaces and experiences
Challenging past assumptions
statelessness, truly embracing REST
abusing markup for "separation of markup and presentation"
control and federation of data
https://secure.flickr.com/photos/dylans/5916167025/
© SitePen, Inc. All Rights Reserved
Multifarious Experiences
© SitePen, Inc. All Rights Reserved
Considerations for Modern Apps
Data vs. presentation
Context switching
Packaging
Testing & monitoring
Choice
Real-time considerations
Convenient APIs and approaches to development
© SitePen, Inc. All Rights Reserved
Ok. But How?
© SitePen, Inc. All Rights Reserved
https://secure.flickr.com/photos/dylans/5205890223/
One Bite at a Time.
© SitePen, Inc. All Rights Reserved
4 Scenarios in Depth
Modules with AMD
Server-Side JavaScript
Data Separation with Object Stores
Shimming and extending CSS
© SitePen, Inc. All Rights Reserved
AMD
© SitePen, Inc. All Rights Reserved
What is AMD?
Stands for Asynchronous Module De%nition
A grassroots standard for de%ning interoperable code modules
Allows the same code to run on both client and server
Originally a CommonJS proposal, now independent
Includes a plugin framework for additional extensibility
Default module system for Dojo 1.7+
© SitePen, Inc. All Rights Reserved
AMD Basics
Replaces dojo.provide, dojo.require, dojo.requireIf, dojo.requireAfterIf, dojo.platformRequire, and dojo.requireLocalization
Creates two global functions, require and define
define.amd is used to indicate that define is actually an AMD-compatible loader and not some random function
Modules are grouped into collections called packages; dojo, dijit, and dojox are all examples of packages
Modules normally have a 1:1 mapping to %les (except when built)
© SitePen, Inc. All Rights Reserved
Why AMD is Awesome
Easy to mix and match code from different projects without risk of name collisions or dependency con$icts
Loads and executes dependencies asynchronously and in parallel; much faster during development
Supports cross-domain loading out of the box, no special builds required
Supports all debuggers out of the box, no need for hacks like debugAtAllCosts or forcing xdomain loading
Trivial to load multiple versions of the same package, or load two different packages with the same name, or patch a single module with another module
© SitePen, Inc. All Rights Reserved
AMD Module Identi%ers
Look like path fragments; e.g. dijit/form/Button
Work a lot like paths, too; relative path fragments like "./" and "../" can be used to refer to other modules within the same package
Necessary for fully portable packages
Can be aliased/overridden to point to different code
Loaders currently differ on how to do this
© SitePen, Inc. All Rights Reserved
Loading non-AMD code
Special module identi%ers can be used to load arbitrary, non-AMD scripts as dependencies, in which case the module's returned value will be unde%ned:
Any identi%er starting with "/"
Any identi%er starting with a protocol (e.g. "http:", "https:")
Any identi%er ending with ".js"
© SitePen, Inc. All Rights Reserved
AMD Modules
De%ned with the define function
Not actually resolved until they they are required (lazy instantiation)
Factory is only called once; the return value is cached by the loader and shared between all modules
Special plugin modules exist to extend loader functionality
© SitePen, Inc. All Rights Reserved
Con%guring AMD Loaders
Given this directory structure, the con%guration would look like so:require({ baseUrl: "js/", packages: [ { name: "dojo", location: "lib/dojo" }, { name: "dijit", location: "lib/dijit" }, { name: "dojox", location: "lib/dojox" }, { name: "my", location: "my" }, { name: "util", location: "util" }, { name: "external", location: "http://foo.com/external" } ]});
© SitePen, Inc. All Rights Reserved
Con%guring AMD Loaders
baseUrl: de%nes the base path for all modules; can be relative or absolute
Relative values are relative to the HTML %le in browsers and relative to the current working directory on servers
packages: de%nes all of the packages registered for the application
name is the name of the package
location is the location of the package; relative paths are relative to baseUrl
main is the name of the module that will be loaded if someone tries to require the package itself; this defaults to "main" (e.g. requiring "dojo" will load the "dojo/main" module)
© SitePen, Inc. All Rights Reserved
Con%guring AMD Loaders
Many other con%guration options exist; only packages is really necessary for a working application
If baseUrl and tlmSiblingOfDojo are both not set, Dojo 1.7's loader uses the directory above the dojo/ directory as baseUrl
© SitePen, Inc. All Rights Reserved
require()
require takes three arguments:
configuration: Optional, a con%guration object for the loader
dependencies: Optional, an array of strings as a list of module identi%ers to load before calling the callback
callback: Optional, a function to call when dependencies are loaded
What does it do?
Recon%gures the loader at runtime
Loads modules and executes an optional callback when they are loaded, passing loaded modules into the callback as arguments
© SitePen, Inc. All Rights Reserved
// We're not using the configuration object here,// just an array of requirements and a callbackrequire(["dojo", "populizr/app"], function(dojo, app){ // Do something with dojo and app});
// The same code in the legacy systemdojo.require("populizr.app");dojo.ready(function(){ // Do something with dojo and populizr.app})
require()
© SitePen, Inc. All Rights Reserved
de%ne()
define takes three arguments:
moduleId: Optional, a string to explicitly identify the module
dependencies: Optional, an array of strings as a list of module identi%ers to load before calling the factory
factory: The value of the module, or a function that returns the value of the module
What does it do?
De%nes the value of a module
Typically the moduleId is reserved for the build system - don't explicitly identify your modules!
© SitePen, Inc. All Rights Reserved
// Creating a widget old styledojo.provide("populizr.TemplatedWidget");
dojo.require("dijit._WidgetBase");dojo.require("dijit._TemplatedMixin");
dojo.declare("populizr.TemplatedWidget", [dijit._WidgetBase, dijit._TemplatedMixin], { templateString: dojo.cache("populizr","templates/TemplatedWidget.html");});
Creating a widget before
© SitePen, Inc. All Rights Reserved
// Creating a widget with AMDdefine( ["dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin", "dojo/text!./templates/TemplatedWidget.html"], function(declare, _WidgetBase, _TemplatedMixin, template){ return declare([_WidgetBase, _TemplatedMixin], { templateString: template }); });
// Note how the dependencies map into the function call!
Creating a widget with declare
© SitePen, Inc. All Rights Reserved
// In populizr/config.jsdefine(["populizr/app"], { enabled: true, animDelay: 500});
The value given for a module can also be just a plain object
In this case, the dependencies will still be resolved as normal, but obviously will not be passed to the factory, since it is not a function
de%ne()
© SitePen, Inc. All Rights Reserved
de%ne()
Differences between these two methods:
AMD is less verbose
AMD is fully self-encapsulated; no references to global variables or the module's own package name
Faster scope lookups
Better mini%cation
Impossible to forget a dependency and still have working code
Zero global namespace pollution
Completely portable
© SitePen, Inc. All Rights Reserved
Conditional requires
Use cases for conditional requirements:
Dependencies that cannot be determined until runtime
dojox/gfx uses this concept to decide which rendering engine to use (VML, SVG, canvas, etc)
Modules that you only want to load when a certain condition occurs (con%guration, event, etc)
© SitePen, Inc. All Rights Reserved
Special Module Names
requireContext sensitive require
Relative module lookups don't work with global require
exportsAn object that is the initial value of the module
If you are returning an object with functions de%ned on it, use this instead of creating and returning a new object
© SitePen, Inc. All Rights Reserved
define(["dojo", "require", "dojo/domReady!" ], function (dojo, require) { var debugButton = dojo.create('input', { type: 'button', value: 'Debug' }, dojo.body());
dojo.connect(debugButton, "click", function () { require([ "./debugger/console" ], function (console) { console.open(); }); });});
Special Module Names
© SitePen, Inc. All Rights Reserved
Plugins
Extend AMD loaders in lots of useful ways
Common plugins available with most loaders are "text", "i18n", and "domReady"
Plugin dependencies are identi%ed by the exclamation point in the module identi%er: "dojo/text!", "dojo/i18n!", "dojo/domReady!"
Data to the left of the "!" identi%es the plugin to load; data to the right of the "!" is passed to the plugin for processing
© SitePen, Inc. All Rights Reserved
// in populizr/quoteLogger.jsdefine([ "dojo/text!./quotes.txt" ], function (quotes) { // quotes will simply be the content of the file, // so we'll split on newlines var quotes = quotes.split("\n"); // Write out a random quote to the console console.log(quotes[Math.floor(quotes.length * Math.random())]);});
Loads a string from a %le
Replaces dojo.cache
Used mostly for loading template strings, but can load any string
Build system interns strings loaded using dojo/text, just like dojo.cache
Compatible with RequireJS's text plugin
dojo/text
© SitePen, Inc. All Rights Reserved
define( [ "dojo/i18n!dijit/nls/common", "dojo/i18n!dijit/nls/common/it" ], function (common, commonIT) { console.log(common.buttonCancel); // "Cancel" console.log(commonIT.buttonCancel); // "Annula" });
Loads an internationalization bundle
Replaces dojo.requireLocalization and dojo.getLocalization
Compatible with RequireJS's i18n plugin
dojo/i18n
© SitePen, Inc. All Rights Reserved
define([ "dojo/domReady!" ], function () { console.log("DOM is ready!");});
Ensures the module does not resolve until the DOM is ready
Replaces dojo.ready
Compatible with RequireJS's domReady plugin
dojo/domReady
© SitePen, Inc. All Rights Reserved
// in populizr/configureEvents.jsdefine( [ "dojo/has!dom-attachEventListener?./events/w3cHandlers:./events/ieHandlers" ], function (eventHandlers) { // Do something with eventHandlers });
Allows modules to be conditionally loaded, using has.js features
Replaces dojo.requireIf
dojo/has
© SitePen, Inc. All Rights Reserved
Portable Modules
moduleId should never be speci%ed explicitly in a de%ne call (it is for build tools)
dojo.declare should never specify the name of the class being declared (unless creating declarative widgets)
If you want to create private classes, remember you can just assign the return value of dojo.declare to a local variable
Dependencies to modules within a package should always use relative module identi%ers
© SitePen, Inc. All Rights Reserved
Portable Modules
Using global variables is verboten
There are some areas where this is still required (some Dijits break the rules and declare multiple classes), but should improve beyond 1.7
This is especially relevant if you are de%ning a module without a factory function; if you have any direct dependencies, you should be using a factory function
Conditional requires with relative module identi%ers must use a context-sensitive require
© SitePen, Inc. All Rights Reserved
Caveats
Speci%cation is still in $ux, making true interoperability difficult
Some examples here only work in the Dojo 1.7 loader
The spec has been agreed upon by Dojo, MooTools, and jQuery
There are actually no other real caveats, AMD is awesome
© SitePen, Inc. All Rights Reserved
https://github.com/kriszyp/commonjs-package-template/blob/master/component.js
Module Template
© SitePen, Inc. All Rights Reserved
60 Packages and growinghttp://packages.dojofoundation.org/
Dojo Foundation Packages
© SitePen, Inc. All Rights Reserved
Server-Side JavaScript
© SitePen, Inc. All Rights Reserved
Persevere
REST server for HTML5/Ajax applications
JavaScript persistence framework
Pluggable storage: MongoDB, Redis, CouchDB, MySQL, etc.
Real-time data noti%cations
High performance, asynchronous, scalable
End-to-end JavaScript
SSJS: Extends Node.js or Narwhal+Jack (and perhaps Ringo)
© SitePen, Inc. All Rights Reserved
Persevere Design Philosophy
Designed for applications with signi%cant client-side logic
Thin-server applications, zero to minimal server-side code needed
Standards-based, HTTP/REST
Promise-based asynchronicity for scalability and composibility
Modular design, JavaScript everywhere
Each package can be used on its own
Some can be used in browser too
© SitePen, Inc. All Rights Reserved
Packages/Sub-Projects
Persevere consists of a number of sub-projects
Cohesively come together for full JavaScript end-to-end stack
© SitePen, Inc. All Rights Reserved
Packages/Sub-Projects
Pintura - JSGI based RESTful web framework (standard HTTP middleware API)
Perstore - Persistence framework
Tunguska - Distributed pub/sub framework with Comet noti%cations
RQL - Resource Query Language engine
Promised-IO - Promise-based IO with cross-platform normalization
© SitePen, Inc. All Rights Reserved
Packages/Sub-Projects (cont.)
Patr - Promise-based asynchronous test runner
Persevere - Client side data explorer, dependency set
Jsgi-node - JSGI middleware for Node
Multi-node - Scales Persevere across multiple process
Templify - JavaScript template engine
JSON Schema - JSON Schema validator and link handler
© SitePen, Inc. All Rights Reserved
https://github.com/kriszyp/perstore/blob/master/package.json
Each Package is an AMD Module!
© SitePen, Inc. All Rights Reserved
Persevere Example Wiki
Good starting point
Project layout
Top level app.js
security
models, page, page-change
wiki media handler
© SitePen, Inc. All Rights Reserved
Pintura
HTTP/REST Interaction
GET /Model/id - Get object
POST /Model/ - Create object
PUT /Model/id - Full update (or create) object
POST /Model/id - Incremental update object
DELETE /Model/id - Delete object
GET /Model/?name=value - Query for objects
© SitePen, Inc. All Rights Reserved
newApp = MiddleWare(app); // take an app, add functionality
appWithProtection = // compose functionality CSRFDetect( Session( Authentication(app) ) );
Set of Middleware components
cross-site request forgery protection
cross-domain
authentication
Many more
Pintura
© SitePen, Inc. All Rights Reserved
Pintura
Security
Authentication and delegation to authorization mechanisms
Error handling - conversion to HTTP status codes
Content negotiation
Negotiates best media type for a resource
Bulk updates via message/JSON
Range requests
Uses HTTP range units for data paging
© SitePen, Inc. All Rights Reserved
Perstore
Persistence framework for data model construction
Data models API based on HTML5 IndexedDB API (get, query, put, delete)
De%ne property constraints using JSON Schema
Perstore provides validation
De%ne prototype of objects
Provides a transaction manager
© SitePen, Inc. All Rights Reserved
DataModel.query().eq(“name”, “Smith”).sort(“age”).forEach(function(item){ // act on each item in result set});
Pluggable data stores
MongoDB, Redis, CouchDB, MySQL, in-memory
Store wrappers used like middleware to add functionality
Data models are a store wrapper
Chainable querying
Perstore
© SitePen, Inc. All Rights Reserved
Persevere Template
Using as a starting point for new applications
Templates for:
Model %les
Security
HTTP con%guration
© SitePen, Inc. All Rights Reserved
Persevere Explorer
Data model explorer from the browser
Provides visual interface to data
Edit data directly in explorer
© SitePen, Inc. All Rights Reserved
Objects Stores and IndexedDB
© SitePen, Inc. All Rights Reserved
Why Object Store?
Separate UI from data handling
Independent evolution of UI components and data components
Object Store API redone in 1.6, follows the HTML5 IndexedDB object store API.
Positioned as successor to Dojo Data API
Also aligns with dojox.storage API
© SitePen, Inc. All Rights Reserved
Data Backed Objects
A uniform API can provide access to data that comes from any source
In Dojo
Many widgets
The Grid
Charting
Django Template Language
© SitePen, Inc. All Rights Reserved
Dojo Store Architecture
Tree Grid ComboBox
CustomStoreJsonRestMemory
Dojo Store API
© SitePen, Inc. All Rights Reserved
What it Provides
Uniform data access layer
Primarily an API speci%cation, but Dojo and DojoX include several implementations of various stores
Variable feature set, with feature discovery
Data is represented as JavaScript objects
© SitePen, Inc. All Rights Reserved
Responsibility of Stores
Stores may delegate responsibilities to the server
Associate Items w/ Identifiers
Handle Queries
Sort Data
Save Data Changes
Trigger Notifications
© SitePen, Inc. All Rights Reserved
Design Philosophy
Feature Detection LayerNo Separate Interfaces; Implement What is Needed
Simple Core APIEasy to Implement
Object Property MutationUse Plain JS Objects, Directly Access & Mutate Properties
(instead of data items)
© SitePen, Inc. All Rights Reserved
Resource Oriented Programming
REST concepts applied to programming
Uniform interface
Layering, store wrappers can be used to add functionality
Easy to implement simple store, add wrappers for more advanced capability
Cacheable
© SitePen, Inc. All Rights Reserved
Promise-Based, Functional
Same API for sync and async stores
async returns promises instead of values
sync stores can be used without callbacks for simplicity
dojo.when makes it easy to use stores generically (sync or async)
Highly functional query results, useful iterative functions
Noti%cations built around query results
© SitePen, Inc. All Rights Reserved
Dojo Object Store API
© SitePen, Inc. All Rights Reserved
Basic API
get(id, options) - Gets an object by identity
query(query, options) - Performs a query
put(object, options) - Stores/updates an object
add(object, options) - Adds an object to the store
remove(id, options) - Deletes an object
getIdentity(object) - Get the identity from an object
© SitePen, Inc. All Rights Reserved
foodStore = new dojo.store.JsonRest({ target: "/Food/"});
foodStore.get("cherry").then(function(cherry){ cherry.color = "red"; foodStore.put(cherry);});foodStore.remove("pickle");
foodStore = dojo.store.Observable(foodStore);
var query = foodStore.query({color:"red"});query.forEach(function(food){...});query.observe(function(object, oldIndex, newIndex){...});
Simple Example
© SitePen, Inc. All Rights Reserved
Query Results
Query results object includes methods:
forEach
map
%lter
Based on Array methods, but always there, and may be asynchronous
total - count of all items when a range is used (can be a promise)
Provided by dojo/store/util/QueryResults
© SitePen, Inc. All Rights Reserved
var query = foodStore.query({color:"red"});var renderedNodes = [], i = 0;query.forEach(function(food){ renderedNodes[i++] = renderFood(food);});query.observe(function(food, oldIndex, newIndex){ // on a data change if(oldIndex > -1){ var oldNode = renderedNodes.splice(oldIndex, 1); dojo.destroy(oldNode); } if(newIndex > -1){ renderedNodes.splice(newIndex, 0, renderFood(food)); }});dojo.when(query.total, function(total){ renderTotal(total + " total foods");});dojo.when(query, renderDone);
Using Query Results in a Widget
© SitePen, Inc. All Rights Reserved
Query Engines
Pluggable engine
Used by client-side store (Memory) for %ltering
Default is provided (dojo.store.util.SimpleQueryEngine), you can override with custom or alternate engine
RQL makes a good alternate engine
https://github.com/kriszyp/rql
© SitePen, Inc. All Rights Reserved
ProvidedObject Stores
© SitePen, Inc. All Rights Reserved
Core Stores
Concrete Stores
Memory - In memory
JsonRest - Connected to store through HTTP/REST
DataStore - Adapter for old Dojo Data stores
Store Wrappers
Observable
© SitePen, Inc. All Rights Reserved
dojo/store/Memory store
Similar to ItemFileReadStore/ItemFileWriteStore
Provide a set of data with the data argument
Uses client-side %ltering/querying
Very simple and lightweight
© SitePen, Inc. All Rights Reserved
dojo/store/JsonRest
Server-side store
Similar to old JsonRestStore
Follows HTTP/REST interface
GET, PUT, POST, DELETE
Lightweight, little work done on client-side
© SitePen, Inc. All Rights Reserved
dojo/store/DataStore
Adapter for legacy Dojo Data stores
Provide a Dojo Data store, returns an object store
Can be used by new widgets with older stores
© SitePen, Inc. All Rights Reserved
dojo/data/ObjectStore
Adapter for legacy Dojo Data widgets
Provide an object store, returns an Dojo Data store
Can be used by legacy widgets with newer stores
© SitePen, Inc. All Rights Reserved
// Create the memory-based object storememoryStore = new MemoryStore({ data: data});
// Create the dojo.data adapterdataStore = new ObjectStore({ objectStore: memoryStore, labelProperty: "author"});
// Pass it to the new treetree = new Tree({ store: dataStore, onDblClick: function(item){ alert(item.content); }}, dojo.byId("tree"));
Example: Using Object Store with Adapter
© SitePen, Inc. All Rights Reserved
Store Wrappers
© SitePen, Inc. All Rights Reserved
Store Wrapper
Takes a store, returns one with added functionality
Cache, validate, etc.
Like middleware for stores
© SitePen, Inc. All Rights Reserved
dojo/store/Cache
Provides caching of a master store to a cache store
Typical con%g:
dojo/store/JsonRest is master
dojo/store/Memory is caching store
Useful when data to be remotely retrieved, but frequently locally accessed
© SitePen, Inc. All Rights Reserved
dojo/store/Observable
Designed to notify listeners of how data changes affect rendered query results, rather than just notifying.
Preserves sort order
Omits new objects that don't match %lter
Adds changed objects that do match %lter now
Widgets can observe() a result set and properly update UI
© SitePen, Inc. All Rights Reserved
// First wrap a storestore = new dojo.store.Observable(store);
// Now we can queryvar results = store.query({name:"value"}, {start:0, count:10});
// And observe the resultsresults.observe(function(changedObject, removedFromIndex, insertedIntoIndex){ // Notified of changes});
Store wrapper for noti%cations, can wrap any store
Adds observe() method to query results
dojo/store/Observable
© SitePen, Inc. All Rights Reserved
Handle Observed Events
If no query engine (JsonRest by default), index won't be provided (not known)
Store Event Observed
removedFromIndex insertedIntoIndex
Both WholeItem was moved
Both EqualUpdated, not moved
Both -1Positions not known
-1Wasn’t in result set before
-1Removed from result set
© SitePen, Inc. All Rights Reserved
socket.on("message", function(event){ store.notify(event.object, event.existingId);});
Observable also adds notify() method
Call notify() to notify of changes from server
Comet Noti%cations with Observable
© SitePen, Inc. All Rights Reserved
Hierarchy
Implement getChildren for hierarchical stores, to get the children
Two hierarchy strategies:
Objects have a children array
Preserves/indicates order of children
Useful for smaller lists of children
Objects have a parent reference
Query by parent to get children
Useful for large lists of unordered children
© SitePen, Inc. All Rights Reserved
XStyle
© SitePen, Inc. All Rights Reserved
XStyle
Framework for shimming and extending CSS
Handles loading CSS
Parsing CSS
Uses CSS plugins to handle speci%c shims and extensions
© SitePen, Inc. All Rights Reserved
Design Philosophy
Future-oriented
Embrace and enable CSS3 and HTML5 technologies
Write code that will gradually get less dependent on framework
Learn technologies that you will continue to need to know
Leverage familiar paradigms
CSS3
Only load what is needed
Lighter loads on modern browsers
© SitePen, Inc. All Rights Reserved
Design Philosophy
Presentation Separation
CSS is the presentation layer for HTML
Stop abusing HTML!
Progressive Loading
Modules don’t encourage progressive loading
Shims and extensions are explicit, no magic
Performance
Need to control when applied, under some situations shims can have more performance degradation then is worth it
© SitePen, Inc. All Rights Reserved
.my-class {border-radius: 5px;box-shadow: 10px 10px 5px #999;transition: 0.5s ease-in;
}
.my-class:hover {color: rgba(255,255,100,100);
}
Shimming/Poly%lling
© SitePen, Inc. All Rights Reserved
@import url(xstyle/shims.css);
.my-class {border-radius: 5px;box-shadow: 10px 10px 5px #999;transition: 2s ease-in;
}
.my-class:hover {color: rgba(255,255,100,100);
}
Shimming/Poly%lling
© SitePen, Inc. All Rights Reserved
Shimming
De%ne properties with
x-property {...}
De%ne pseudos with
x-pseudo {...}
Possible values
default
pre%x
module: require(shim/module)
Generally use native/default %rst if available
© SitePen, Inc. All Rights Reserved
x-property {border-radius: default, prefix;box-shadow: default, prefix;transition: default, prefix, require(xstyle/shim/transition);
}x-pseudo {hover: default, require(xstyle/shim/pseudo);
}// ^imported shims.css.my-class {border-radius: 5px;box-shadow: 10px 10px 5px #999;transition: 2s ease-in;
}
.my-class:hover {color: rgba(255,255,100,100);
}
Shimming/Poly%lling
© SitePen, Inc. All Rights Reserved
Extensions
Works just like shims
Generally don’t use native/%rst, without a standard we need to preserve behavior
© SitePen, Inc. All Rights Reserved
@import url(xstyle/ext.css);.my-widget {-x-widget: {type: dijit/Tree;store: treeStore;
};-x-resizable: xy;border-radius: 5px;
}
Extensions
© SitePen, Inc. All Rights Reserved
Shimming HTML5 with Extensions
Use :unsupported pseudo to apply speci%c widgets when functionality is missing.
© SitePen, Inc. All Rights Reserved
@import url(xstyle/ext.css);progress:unsupported {-x-widget: {type: dijit/ProgressBar;
};}
input[type=range]:unsupported {-x-widget: {type: dijit/form/HorizontalSlider;
};}
Shimming HTML5 with Extensions
© SitePen, Inc. All Rights Reserved
Fixing @import
Fix deep level @imports in old IE
Enforces @import-once behavior on browsers
Predictable style overrides
© SitePen, Inc. All Rights Reserved
Spin off: put-selector
CSS Selector based DOM node creation and manipulation
One of our favorite new tools
Faster than templating
More consistent
Keep context within code
© SitePen, Inc. All Rights Reserved
put(target, ‘div’);put(target, ‘div.my-class’);put(‘input[type=checkbox].my-input’);put(target, ‘.add-a-class’);put(target, ‘[tabIndex=1]’);put(‘span.has-content’, ‘Hello, World’);put(target, ‘div.has-child’, child,‘div.great-great-grandchild’);put(target, ‘+div.after-target+div.after-that’);put(target, ‘-div.before’);put(‘table tr td << tr td’);put(‘div label.name $ +input[type=text][value=$’, ‘Name’, ‘Value’);put(target, ‘!remove-class[!remove-attribute]’);
Fun with put-selector
© SitePen, Inc. All Rights Reserved
define([‘xstyle/has-class’], function(hasClass){ hasClass(‘mozilla’, ‘no-quirks’, ‘ie-6’, ‘ie-6-7’);});
...
<html class=”has-mozilla has-no-quirks”>
...
<html class=”has-ie-6 has-ie-6-7”>
xstyle/has-class - has() based doc classes
© SitePen, Inc. All Rights Reserved
Other Future Possibilities
Generative CSS
Create elements for the rules in CSS
Skip the middleman!
JSON StyleSheets
StyleSheet to be applied to JSON
Could be generative
Could be used on non-HTML platform
Return of JSSS </evil laugh>
© SitePen, Inc. All Rights Reserved
Result: Modular Tools
Tools to mix and match to create your app
Separate data from UI logic simply and seamlessly
Modular enough for very simple projects, $exible and consistent enough to handle the most challenging, feature-rich web apps
© SitePen, Inc. All Rights Reserved
© SitePen, Inc. All Rights Reserved
SitePen: We help our clients build great apps.
Web App Development, Design, Advice
Support & Training
Strong advocates and contributors of FOSS
Works with some amazing companies and organizations: