|
1
|
|
|
2
|
|
|
3
|
- What
- Why
- How you can do it yourself
|
|
4
|
|
|
5
|
- Modern web browser
- No installs
- No security dialogs
- Standards
- Ajax / dhtml / html / css
|
|
6
|
- Occasionally offline
- Occasionally connected
- Airplane is boarding
- Train in a tunnel
- Wifi is “secured”
- Evdo hiccups
|
|
7
|
- Already (re)learning DHTML, Ajax…
- Add just a little bit more…
- Only a few more tricks…
|
|
8
|
- Get more dates
- Make more money
- Look like a hero
|
|
9
|
|
|
10
|
|
|
11
|
|
|
12
|
|
|
13
|
- Use the TrimPath Junction framework
- Or, do it yourself / write your own
- As easy as Ajax
|
|
14
|
- Everyone has one, maybe even you
- Starts so simple
- 15 line wrapper around XMLHttpRequest
- What about for going occasionally offline?
|
|
15
|
- …to go occasionally offline
|
|
16
|
- Client side data cache
- That can work offline
|
|
17
|
- Modern browsers keep dhtml DOM tree intact during a File | Save Page As
- Keep your data in the DOM tree
- myHiddenDataDiv.innerHTML = bigString
- Whenever user saves the HTML page, you’re ok
- User must explicitly File | Save Page As
|
|
18
|
- Flash 8 Storage
- Flash to JavaScript bridge
- Seamless!
- Except, when you hit quantum level of storage usage, Flash pops up a
warning
|
|
19
|
- Internet Explorer’isms
- IE persistence
- IE offline data
- Future is already here
- And in the case of Internet Explorer is already widely distributed
|
|
20
|
- DOM Page Saving Technique
- TiddlyWiki & friends
- Num Sum
- Next Action
- Flash Storage Technique
- AMASS demos
- Tiwywiki / AFLAX
- http://ajaxian.com/archives/take-it-with-you-wiki
- ideaShrub
|
|
21
|
- Persistence (yes)
- Synchronization
|
|
22
|
- Data / record level semantics
- Tracking deltas
- Change requests, not changes
- INSERTs only
- Unique ID gen
- Or, just punt
|
|
23
|
- Persistence (yes)
- Synchronization (yes)
- Client side API
|
|
24
|
- Visual Basic Style
- Rails Style
- Yes
- Write Once Run Anywhere
|
|
25
|
- SQL on the server
- SQL on the client
- Aside: Firefox future
|
|
26
|
- MVC Framework for JavaScript
- Rails-like API with client-side SQL
- Designed for WORA
- Write once, run anywhere (client or server)
- Server runs Rhino
- Designed for >1 storage provider
- DOM Page, Flash or other (Derby, SQLite)
- MySQL when running on server
|
|
27
|
- What are the core tricks?
|
|
28
|
- How powerful is JavaScript?
|
|
29
|
- Thank you, Douglas Crockford
- Thank you, Brendan Eich
|
|
30
|
|
|
31
|
- JavaScript’s dynamic scoping
- Change the scope chain at runtime
|
|
32
|
- x = 123;
- alert(x);
- obj = { ‘x’: ‘joel’ }
- alert(x);
- with (obj) {
- alert(x);
- obj[‘x’] = ‘spolsky’;
- alert(x);
- }
|
|
33
|
- Domain specific mini languages are easy
- JSP
- SQL
- Obj-Relational mapping
- Spreadsheet formulas
- Prolog
- Scheme
- Ruby
- Layout constraints
- Synchronization constraints
|
|
34
|
- JST == JavaScript Templates
- <h1>Welcome Back!
-
${Customer.name}</h1>
- Loops, macros, modifiers, minify
- Smarty, Freemarker
|
|
35
|
- Hand rolled parser
- Generate JavaScript function string
- with (context) {
- out.push(“<h1>Welcome Back! ”)
- out.push(Customer.name)
- out.push(“</h1>”)
- }
- Eval and return it
|
|
36
|
- resultStr = template.process(context)
- someDiv.innerHTML = resultStr
- JST Engine -- 397 LoC
|
|
37
|
|
|
38
|
- RegExps to transform SQL to TQL
- SELECT(Emp.name, Emp.salary,
- FROM(Emp, Dept),
- ORDER_BY(Emp.name))
- Eval the TQL (it’s just JavaScript)
- Emp and Dept are JavaScript objects that represent the table schema.
- schema = {
- Emp: { …bunch-o-column-definitions… },
- Dept: { …more-column-definitions… }
- }
|
|
39
|
- with (TQL_KEYWORDS) {
- with (schema) {
- SELECT(Emp.name, Emp.salary,
- FROM(Emp, Dept),
- ORDER_BY(Emp.name))
- }
- }
|
|
40
|
- with (data_tables) {
- crossJoinTuple = {}
- for (i = 0; i < Emp.length; i++) {
- crossJoinTuple.Emp = Emp[i];
- for (j = 0; j < Dept.length; j++) {
- crossJoinTuple.Dept = Dept[j]
- if (whereClause(crossJoinTuple))
-
addToResultSet(crossJoinTuple)
- }
- }
- }
|
|
41
|
- with (crossJoinTuple) {
- if (Emp.salary > 100 &&
- Emp.dept_id == Dept.id)
- return true;
- return false;
- }
|
|
42
|
- CROSS & LEFT OUTER JOINs
- TABLE & COLUMN aliases
- WHERE, ORDER BY
- GROUP BY, HAVING
- Aggregates
- SQL engine in 668 LoC
|
|
43
|
- Clone or port the Rails API
- Into JavaScript
- Leverages Rails goodness
- Lazy approach
- TrimPath Junction -- 1244 LoC
|
|
44
|
- Milestone = function() { }
- with (modelFor('Milestone')) {
- belongsTo('Creator', { modelName : 'Person' });
- belongsTo('Domain', { modelName : 'Org' });
- belongsTo('Project');
- belongsTo('Assignee', { modelName : 'Person' });
- hasMany('Messages');
- hasMany('TodoLists');
- }
|
|
45
|
- Milestone.findRecentByProject =
- function(projectId, date) {
- return Milestone.findAll(
- “Milestone.projectId = ?” +
- “ AND Milestone.createdAt > ?”,
- [ projectId, date ]);
- }
|
|
46
|
- MilestoneController = function() {
- this.index = function(req, res) {
- res.milestones = Milestone.findAll();
- }
- this.show = function(req, res) {
- res.milestone = Milestone.find(req['objId']);
- }
- …
- }
|
|
47
|
|
|
48
|
- When running on the server
- Junction uses layout name just like Rails
- When running on the client
- Junction uses the layout name to…
- O = document.getElementById(layoutName)
- O.innerHTML = resultOfJSTRender
- Somewhat like HAJAX
|
|
49
|
|
|
50
|
- DOM page storage limits
- TrimPath Junction written to support pluggable persistence engines
|
|
51
|
- Sync issues are hard
- Solutions
- Data / record level synchronization
- Send deltas
- Change requests, not changes
|
|
52
|
|
|
53
|
- Build your own!
- Do it better!
|
|
54
|
- Exists on Brad Neuberg’s laptop
- Which is not widely distributed yet
|
|
55
|
|