Selector-based View Composition William Zeller and Edward Felten - - PowerPoint PPT Presentation

selector based view
SMART_READER_LITE
LIVE PREVIEW

Selector-based View Composition William Zeller and Edward Felten - - PowerPoint PPT Presentation

Selector-based View Composition William Zeller and Edward Felten Princeton University http://svc.from.bz What is SVC? Modification to Model-View-Controller (MVC) architecture Provides automatic progressive enhancement (Ajaxification)


slide-1
SLIDE 1

Selector-based View Composition

William Zeller and Edward Felten Princeton University http://svc.from.bz

slide-2
SLIDE 2

What is SVC?

  • Modification to Model-View-Controller (MVC)

architecture

  • Provides automatic progressive enhancement

(Ajaxification) of web pages.

WebApps '10 - June 24, 2010 2

slide-3
SLIDE 3

State of Ajax on the Web

  • Allows interactivity
  • Expected by users
  • Only works if browser supports JavaScript

WebApps '10 - June 24, 2010 3

slide-4
SLIDE 4

Ajax and Non-JavaScript Browsers

  • Why support non-JavaScript browsers?

– JS may be disabled – Users with disabilities – Search engines – Other annoyances if only JS supported

  • E.g., “Open in new tab” may not work

WebApps '10 - June 24, 2010 4

slide-5
SLIDE 5

Progressive Enhancement

  • Standard "best practice" for supporting both

JS and non-JS browsers

  • Idea:
  • 1. Create working, non-JS version of site
  • 2. Add JavaScript to "enhance site" by adding

interactivity

  • Difficult

– All Ajax functionality needs to be duplicated

WebApps '10 - June 24, 2010 5

slide-6
SLIDE 6

MVC before Progressive Enhancement

Controller Request View Models Browser

HTML

Server Client

WebApps '10 - June 24, 2010 6

slide-7
SLIDE 7

MVC after Progressive Enhancement

Controller Request Non-Ajax View Models Browser

HTML

Ajax? Ajax View

JSON/XML

JavaScript

Client Server

Yes No

WebApps '10 - June 24, 2010 7

slide-8
SLIDE 8

SVC

  • Provided as server-side API
  • API is used to compose views together
  • (CSS) selectors are used to identify the point of

composition

  • Advantages:

– Write view update code once – No need to write JavaScript (for actions supported by SVC) – Language agnostic – Existing template code and JavaScript unaffected

WebApps '10 - June 24, 2010 8

slide-9
SLIDE 9

Why Selectors?

  • Selectors, e.g.,

– #foo (element with id "foo") – .foo (elements with class "foo") – div > a (select all 'a' elements that are children

  • f 'div' elements)
  • Familiar to developers (CSS)
  • Becoming more common in JS frameworks

– Closure, Dojo, jQuery, MooTools, Prototype, YUI

WebApps '10 - June 24, 2010 9

slide-10
SLIDE 10

SVC

Controller Request Models Browser

HTML JSON

SVC JS Views View Composition SVC

Server Client

WebApps '10 - June 24, 2010 10

slide-11
SLIDE 11

What does SVC look like?

$svc->initial('example'); // assume example is //<p id="msg"></p> $svc->text('#msg', 'My message'); $svc->addClass('p', 'highlight');

  • Non-Ajax request response (HTML):

<p id="msg" class="highlight">My message</p>

  • Ajax Request response (JSON)

[['text', ['#msg', 'My message']], ['addClass', ['p', 'highlight']]]

WebApps '10 - June 24, 2010 11

slide-12
SLIDE 12

SVC

Controller Request Models Browser

HTML JSON

SVC JS Views View Composition SVC

Server Client

WebApps '10 - June 24, 2010 12

slide-13
SLIDE 13

SVC Client-side JavaScript

  • SVC client-side JS applies JSON to current

document

  • In previous example:

[['text', ['#msg', 'My message']], ['addClass', ['p', 'highlight']]]

– Sets the text of any element with ID 'msg' – Adds class "highlight" to any paragraph tag.

  • Size: 1.7KB, requires jQuery (could be written on

top of other libraries as well)

WebApps '10 - June 24, 2010 13

slide-14
SLIDE 14

SVC

Controller Request Models Browser

HTML JSON

SVC JS Views View Composition SVC

Server Client

WebApps '10 - June 24, 2010 14

slide-15
SLIDE 15

How does SVC perform actions on server-side?

  • JavaScript is used to update view on client-

side, but what about server?

  • Need to compose view on server-side for non-

JS requests

– Requires selector support and DOM manipulation

  • Our version of SVC uses WebKit (WebCore)

– Actions implemented in C++ extension to PHP

WebApps '10 - June 24, 2010 15

slide-16
SLIDE 16

How does SVC Progressively Enhance?

  • SVC can now respond to both Ajax and non-

Ajax requests

  • But how are Ajax requests generated?
  • Developer has used SVC on server
  • Writes HTML without JavaScript in mind (e.g.,

...a href="/foo">Link</a>)

WebApps '10 - June 24, 2010 16

slide-17
SLIDE 17

How does SVC Progressively Enhance?

  • On server-side, SVC adds the class

"svc_rewrite" to any element which should use JavaScript to load request

  • On client-side, SVC adds onclick or onsubmit

event handlers to any element with the class "svc_rewrite"

WebApps '10 - June 24, 2010 17

slide-18
SLIDE 18

When does SVC Progressively Enhance Pages?

  • SVC does not know when loading a link using

Ajax is appropriate

– We do not want to transmit page to server to see if manipulating the DOM makes sense

  • SVC provides API to define which links should

be rewritten to use Ajax

$svc->rewrite('a', 'b')

(On page "b", rewrite all links to "a")

WebApps '10 - June 24, 2010 18

slide-19
SLIDE 19

What can be done with SVC?

  • We implemented the following actions:

– addClass – append – attr – css – html – prepend – remove – removeClass – text

WebApps '10 - June 24, 2010 19

slide-20
SLIDE 20

What can be done with SVC?

  • SVC can be easily extended.
  • Could be written once and distributed as SVC

plugins

  • Only requirement is that action can be

performed on client and server.

WebApps '10 - June 24, 2010 20

slide-21
SLIDE 21

How are Actions Added to SVC?

  • Implement action on client and server.
  • E.g., add before action

– On server, use PHP or scripting language to perform update to view – On client, use JavaScript to perform equivalent action – SVC users can then call before in any of their code.

WebApps '10 - June 24, 2010 21

slide-22
SLIDE 22

Adding non-DOM Actions to SVC

  • Actions we've seen manipulate the DOM
  • SVC actions not limited to DOM manipulation

– Only requirement is to server/client equivalence

  • E.g., redirect

– On server, output HTTP header – On client, call window.location

WebApps '10 - June 24, 2010 22

slide-23
SLIDE 23

SVC Overhead

  • Non-Ajax requests (initial and non-JS requests)

– Page needs to be constructed on server – Requires parsing, running selectors and actions – DOM output can be cached.

  • Ajax requests

– List of SVC actions sent directly to client – Modifications performed by client JS – Essentially no server overhead

WebApps '10 - June 24, 2010 23

slide-24
SLIDE 24

SVC Server-side Parsing Overhead

  • E.g., SVC parsed 80% of the sites in 15ms
  • DomDocument is an alternative PHP HTML parser
  • 10,000 most popular websites parsed

WebApps '10 - June 24, 2010 24

slide-25
SLIDE 25

SVC Server-side Selector Overhead

  • Our SVC implementation uses WebCore's

querySelectorAll

  • Translated SlickSpeed test to PHP

– Ran 40 selectors against standard 108KB webpage – Ran test 1000 times, mean time of 1.49ms per selector – More details in paper

WebApps '10 - June 24, 2010 25

slide-26
SLIDE 26

SVC Server-side Action Overhead

  • Mean time to insert 0-1MB (64KB increments)
  • 100 runs per size

WebApps '10 - June 24, 2010 26

slide-27
SLIDE 27

SVC Client-side Overhead

  • Our SVC JavaScript wraps jQuery functionality

– E.g., the literal implementation of addClass

addClass: function(selector, className){ $(selector).addClass(className); },

  • Depends on browser, underlying JS library,

action complexity

WebApps '10 - June 24, 2010 27

slide-28
SLIDE 28

Alternatives to SVC

  • GWT, Cappuccino, SproutCore and RJS (Rails

JS)

– Allow server-side creation of JS – Do not provide non-JS browser support

  • Not aware of any other solution that provides

automatic progressive enhancement of pages

  • More comparisons in paper

WebApps '10 - June 24, 2010 28

slide-29
SLIDE 29

Extending SVC

  • Additional Language Support

– Python prototype has been written

  • Simpler than PHP – only requires lxml library
  • Additional client-side libraries

– Currently based on jQuery – Versions could be written for Prototype, Closure, Dojo, etc.

WebApps '10 - June 24, 2010 29

slide-30
SLIDE 30

Conclusion

  • SVC provides automatic progressive

enhancement and compatibility with older browsers

  • SVC allows composition of views using

selectors

  • More info: http://svc.from.bz

Thanks! Questions?

WebApps '10 - June 24, 2010 30

slide-31
SLIDE 31

WebApps '10 - June 24, 2010 31

slide-32
SLIDE 32

Addendum Example: Tabs

  • Page consisting of multiple tabs
  • Tabs should load using Ajax when available

– But work without JavaScript

  • Changing tab requires changing:

– Tab content – CSS class in tab header – Page title

WebApps '10 - June 24, 2010 32

slide-33
SLIDE 33

Tabs Screenshots

  • Tab 1
  • Tab 2

WebApps '10 - June 24, 2010 33

slide-34
SLIDE 34

Tabs Screenshots

  • Tab 1
  • Tab 2

WebApps '10 - June 24, 2010 34

slide-35
SLIDE 35

Tabs Screenshots

  • Tab 1
  • Tab 2

WebApps '10 - June 24, 2010 35

slide-36
SLIDE 36

Tabs Screenshots

  • Tab 1
  • Tab 2

WebApps '10 - June 24, 2010 36

slide-37
SLIDE 37

First Tab Page HTML

<html> <head> <title>First tab page</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li class="selected"><a href="/tab1">First Tab</a></li> <li><a href="/tab2">Second Tab</a></li> <li><a href="/tab3">Third Tab</a></li> </ul> </div> (continued on next page...)

WebApps '10 - June 24, 2010 37

slide-38
SLIDE 38

First Tab Page HTML

<html> <head> <title>First tab page</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li class="selected"><a href="/tab1">First Tab</a></li> <li><a href="/tab2">Second Tab</a></li> <li><a href="/tab3">Third Tab</a></li> </ul> </div> (continued on next page...)

Page title

WebApps '10 - June 24, 2010 38

slide-39
SLIDE 39

First Tab Page HTML

<html> <head> <title>First tab page</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li class="selected"><a href="/tab1">First Tab</a></li> <li><a href="/tab2">Second Tab</a></li> <li><a href="/tab3">Third Tab</a></li> </ul> </div> (continued on next page...)

Tabs header

WebApps '10 - June 24, 2010 39

slide-40
SLIDE 40

First Tab Page HTML

<html> <head> <title>First tab page</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li class="selected"><a href="/tab1">First Tab</a></li> <li><a href="/tab2">Second Tab</a></li> <li><a href="/tab3">Third Tab</a></li> </ul> </div> (continued on next page...)

CSS class showing selected tab

WebApps '10 - June 24, 2010 40

slide-41
SLIDE 41

First Tab Page HTML

(continued...) <div id="content"> First tab content <br/><br/> <b>Bold</b> first tab message. </div> </body> </html>

WebApps '10 - June 24, 2010 41

slide-42
SLIDE 42

First Tab Page HTML

(continued...) <div id="content"> First tab content <br/><br/> <b>Bold</b> first tab message. </div> </body> </html>

Tab content

WebApps '10 - June 24, 2010 42

slide-43
SLIDE 43

Tabs Page without SVC

  • Create site without JavaScript
  • Use JavaScript to add Ajax support

– This is the Progressive Enhancement step

WebApps '10 - June 24, 2010 43

slide-44
SLIDE 44

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { } function tab2() { } function tab3() { } }

WebApps '10 - June 24, 2010 44

slide-45
SLIDE 45

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { } function tab2() { } function tab3() { } }

tab1() runs when /tab1 is requested, etc

WebApps '10 - June 24, 2010 45

slide-46
SLIDE 46

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { } function tab2() { } function tab3() { } }

We don't show tab3() due to space limitations.

WebApps '10 - June 24, 2010 46

slide-47
SLIDE 47

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { } function tab2() { } }

WebApps '10 - June 24, 2010 47

slide-48
SLIDE 48

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); } function tab2() { } }

WebApps '10 - June 24, 2010 48

slide-49
SLIDE 49

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); } function tab2() { } }

Define array with data which will be sent to the view

WebApps '10 - June 24, 2010 49

slide-50
SLIDE 50

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); } function tab2() { $data = array('title' => 'Second tab page', 'tab_num' => 2, 'content' => view('tab2_content')); } }

WebApps '10 - June 24, 2010 50

slide-51
SLIDE 51

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); return view('tab_template', $data); } function tab2() { $data = array('title' => 'Second tab page', 'tab_num' => 2, 'content' => view('tab2_content')); return view('tab_template', $data); } }

WebApps '10 - June 24, 2010 51

slide-52
SLIDE 52

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); return view('tab_template', $data); } function tab2() { $data = array('title' => 'Second tab page', 'tab_num' => 2, 'content' => view('tab2_content')); return view('tab_template', $data); } }

Call view "tab_template" with data array.

WebApps '10 - June 24, 2010 52

slide-53
SLIDE 53

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); return view('tab_template', $data); } function tab2() { $data = array('title' => 'Second tab page', 'tab_num' => 2, 'content' => view('tab2_content')); return view('tab_template', $data); } }

Output interpreted view.

WebApps '10 - June 24, 2010 53

slide-54
SLIDE 54

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); return view('tab_template', $data); } function tab2() { $data = array('title' => 'Second tab page', 'tab_num' => 2, 'content' => view('tab2_content')); return view('tab_template', $data); } }

WebApps '10 - June 24, 2010 54

slide-55
SLIDE 55

Template (tab_template)

<html> <head> <title><?=$title?></title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li <? if ($tab_num == 1) { ?> class="selected" <? } ?> id="tab_1"><a href="/tab1">First Tab</a></li> <li <? if ($tab_num == 2) { ?> class="selected" <? } ?> id="tab_2"><a href="/tab2">Second Tab</a></li> (continued on next page...)

WebApps '10 - June 24, 2010 55

slide-56
SLIDE 56

Template (tab_template)

<html> <head> <title><?=$title?></title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li <? if ($tab_num == 1) { ?> class="selected" <? } ?> id="tab_1"><a href="/tab1">First Tab</a></li> <li <? if ($tab_num == 2) { ?> class="selected" <? } ?> id="tab_2"><a href="/tab2">Second Tab</a></li> (continued on next page...)

Output Title

WebApps '10 - June 24, 2010 56

slide-57
SLIDE 57

Template (tab_template)

<html> <head> <title><?=$title?></title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li <? if ($tab_num == 1) { ?> class="selected" <? } ?> id="tab_1"><a href="/tab1">First Tab</a></li> <li <? if ($tab_num == 2) { ?> class="selected" <? } ?> id="tab_2"><a href="/tab2">Second Tab</a></li> (continued on next page...)

Set CSS class if appropriate

WebApps '10 - June 24, 2010 57

slide-58
SLIDE 58

Template (tab_template)

(continued...) <li <? if ($tab_num == 3) { ?> class="selected" <? } ?> id="tab_3"><a href="/tab3">Third Tab</a></li> </ul> </div> <div id="content"><?=$content?></div> </body> </html>

WebApps '10 - June 24, 2010 58

slide-59
SLIDE 59

Template (tab_template)

(continued...) <li <? if ($tab_num == 3) { ?> class="selected" <? } ?> id="tab_3"><a href="/tab3">Third Tab</a></li> </ul> </div> <div id="content"><?=$content?></div> </body> </html>

Set CSS class if appropriate

WebApps '10 - June 24, 2010 59

slide-60
SLIDE 60

Template (tab_template)

(continued...) <li <? if ($tab_num == 3) { ?> class="selected" <? } ?> id="tab_3"><a href="/tab3">Third Tab</a></li> </ul> </div> <div id="content"><?=$content?></div> </body> </html>

Output content

WebApps '10 - June 24, 2010 60

slide-61
SLIDE 61

Tabs Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); return view('tab_template', $data); } function tab2() { $data = array('title' => 'Second tab page', 'tab_num' => 2, 'content' => view('tab2_content')); return view('tab_template', $data); } }

WebApps '10 - June 24, 2010 61

slide-62
SLIDE 62

Content Templates

tab1_content

First tab content <br/><br/> <b>Bold</b> first tab message. Some content for the second tab.

tab2_content

WebApps '10 - June 24, 2010 62

slide-63
SLIDE 63

Non-Ajax Tabs Example Complete

  • Site works (but no Ajax)
  • Let's enhance!

WebApps '10 - June 24, 2010 63

slide-64
SLIDE 64

Adding Ajax (Main Template)

<html> <head> <title><?=$title?></title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li <? if ($tab_num == 1) { ?> class="selected" <? } ?> id="tab_1"><a href="/tab1">First Tab</a></li> ...

WebApps '10 - June 24, 2010 64

slide-65
SLIDE 65

Adding Ajax (Main Template)

<html> <head> <title><?=$title?></title> <script type="text/javascript" src="jQuery.js"></script> <script type="text/javascript" src="tabs.js"></script> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li <? if ($tab_num == 1) { ?> class="selected" <? } ?> id="tab_1"><a href="/tab1">First Tab</a></li> ...

Add scripts to progressively enhance

WebApps '10 - June 24, 2010 65

slide-66
SLIDE 66

Add Ajax to Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); return view('tab_template', $data); } ... }

WebApps '10 - June 24, 2010 66

slide-67
SLIDE 67

Add Ajax to Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); if (is_ajax()) { return json_encode($data); } else { return view('tab_template', $data); } } ... }

WebApps '10 - June 24, 2010 67

slide-68
SLIDE 68

Add Ajax to Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); if (is_ajax()) { return json_encode($data); } else { return view('tab_template', $data); } } ... }

If Ajax request, return JSON

WebApps '10 - June 24, 2010 68

slide-69
SLIDE 69

Add Ajax to Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); if (is_ajax()) { return json_encode($data); } else { return view('tab_template', $data); } } ... }

Otherwise, output HTML

WebApps '10 - June 24, 2010 69

slide-70
SLIDE 70

Example: Adding Ajax (tabs.js)

$(function() { });

WebApps '10 - June 24, 2010 70

slide-71
SLIDE 71

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { // ... }; $('#tab_header a').click(onTabClk); });

Add click handler to tab links

WebApps '10 - June 24, 2010 71

slide-72
SLIDE 72

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { // ... }; $('#tab_header a').click(onTabClk); });

Function to be called when tab link is clicked

WebApps '10 - June 24, 2010 72

slide-73
SLIDE 73

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { return false; }; $('#tab_header a').click(onTabClk); });

Return false to prevent normal link load

WebApps '10 - June 24, 2010 73

slide-74
SLIDE 74

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { var href = $(this).attr('href'); return false; }; $('#tab_header a').click(onTabClk); });

Extract link URL

WebApps '10 - June 24, 2010 74

slide-75
SLIDE 75

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { var href = $(this).attr('href'); $.getJSON(href, function(data) { // ... process JSON response }); return false; }; $('#tab_header a').click(onTabClk); });

Make JSON request

WebApps '10 - June 24, 2010 75

slide-76
SLIDE 76

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { var href = $(this).attr('href'); $.getJSON(href, function(data) { document.title = data.title; }); return false; }; $('#tab_header a').click(onTabClk); });

Set page title

WebApps '10 - June 24, 2010 76

slide-77
SLIDE 77

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { var href = $(this).attr('href'); $.getJSON(href, function(data) { document.title = data.title; $('#tab_' + data.tabNum).addClass('selected'); }); return false; }; $('#tab_header a').click(onTabClk); });

Set CSS class of new tab

WebApps '10 - June 24, 2010 77

slide-78
SLIDE 78

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { var href = $(this).attr('href'); $.getJSON(href, function(data) { document.title = data.title; $('#tab_' + data.tabNum).addClass('selected'); $('#content').html(data.content); }); return false; }; $('#tab_header a').click(onTabClk); });

Set tab content

WebApps '10 - June 24, 2010 78

slide-79
SLIDE 79

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { var href = $(this).attr('href'); $.getJSON(href, function(data) { document.title = data.title; $('.selected').removeClass('selected'); $('#tab_' + data.tabNum).addClass('selected'); $('#content').html(data.content); }); return false; }; $('#tab_header a').click(onTabClk); });

Remove "selected" CSS class from all elements

WebApps '10 - June 24, 2010 79

slide-80
SLIDE 80

Example: Adding Ajax (tabs.js)

$(function() { var onTabClk = function() { var href = $(this).attr('href'); $.getJSON(href, function(data) { document.title = data.title; $('.selected').removeClass('selected'); $('#tab_' + data.tabNum).addClass('selected'); $('#content').html(data.content); }); return false; }; $('#tab_header a').click(onTabClk); });

WebApps '10 - June 24, 2010 80

slide-81
SLIDE 81

Tabs Example Now Progressively Enhanced

  • Tabs will load using Ajax in JS browsers

WebApps '10 - June 24, 2010 81

slide-82
SLIDE 82

Cost of Progressive Enhancement

  • Requires duplication of view updates.

– Server-side using templates. – Client-side using JavaScript

WebApps '10 - June 24, 2010 82

slide-83
SLIDE 83

Examples of Duplication: Page Title

  • Server-side code
  • Client-side code

<title><?=$title?></title> document.title = data.title;

WebApps '10 - June 24, 2010 83

slide-84
SLIDE 84

Examples of Duplication: Tab Headers

  • Server-side code
  • Client-side code

<li <? if ($tab_num == 1) { ?> class="selected" <? } ?> id="tab_1"><a href="/tab1">First Tab</a></li> <li <? if ($tab_num == 2) { ?> class="selected" <? } ?> id="tab_2"><a href="/tab2">Second Tab</a></li> <li <? if ($tab_num == 3) { ?> class="selected" <? } ?> id="tab_3"><a href="/tab3">Third Tab</a></li> $('.selected').removeClass('selected'); $('#tab_' + data.tabNum).addClass('selected');

WebApps '10 - June 24, 2010 84

slide-85
SLIDE 85

Examples of Duplication: Page Content

  • Server-side code
  • Client-side code

<div id="content"><?=$content?></div> $('#content).html(data.content);

WebApps '10 - June 24, 2010 85

slide-86
SLIDE 86

Tabs Example Using SVC

  • Instead of duplicating view update code, use

SVC API to describe how to compose views

WebApps '10 - June 24, 2010 86

slide-87
SLIDE 87

Example: Non-SVC Controller

<?php class TabsExample extends Controller { function tab1() { $data = array('title' => 'First tab page', 'tab_num' => 1, 'content' => view('tab1_content')); return view('tab_template', $data); } function tab2() { $data = array('title' => 'Second tab page', 'tab_num' => 2, 'content' => view('tab2_content')); return view('tab_template', $data); } }

WebApps '10 - June 24, 2010 87

slide-88
SLIDE 88

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { // } function tab2() { // ... } }

WebApps '10 - June 24, 2010 88

slide-89
SLIDE 89

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { // } function tab2() { // ... } }

tabbase() creates an SVC list consisting of only the template "tabbase_template"

WebApps '10 - June 24, 2010 89

slide-90
SLIDE 90

Example: Template (tabbase)

<html><head> <title></title> <link rel="stylesheet" type="text/css" href="style.css"/> </head><body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li id="tab_1"><a href="/tab1">First Tab</a></li> <li id="tab_2"><a href="/tab2">Second Tab</a></li> <li id="tab_3"><a href="/tab3">Third Tab</a></li> </ul> </div> <div id="content"></div> </body></html>

WebApps '10 - June 24, 2010 90

slide-91
SLIDE 91

Example: Template (tabbase)

<html><head> <title></title> <link rel="stylesheet" type="text/css" href="style.css"/> </head><body> <div id="tab_header"> <h1>Tabs Example</h1> <ul> <li id="tab_1"><a href="/tab1">First Tab</a></li> <li id="tab_2"><a href="/tab2">Second Tab</a></li> <li id="tab_3"><a href="/tab3">Third Tab</a></li> </ul> </div> <div id="content"></div> </body></html>

Like "tab_template", but all content is empty.

WebApps '10 - June 24, 2010 91

slide-92
SLIDE 92

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { // } function tab2() { // ... } }

WebApps '10 - June 24, 2010 92

slide-93
SLIDE 93

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); } function tab2() { // ... } }

WebApps '10 - June 24, 2010 93

slide-94
SLIDE 94

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); } function tab2() { // ... } }

Start with output of tabbase()

WebApps '10 - June 24, 2010 94

slide-95
SLIDE 95

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); } function tab2() { // ... } }

WebApps '10 - June 24, 2010 95

slide-96
SLIDE 96

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); } function tab2() { // ... } }

Update the title

WebApps '10 - June 24, 2010 96

slide-97
SLIDE 97

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); $this->svc->removeClass('.selected', 'selected'); } ... }

WebApps '10 - June 24, 2010 97

slide-98
SLIDE 98

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); $this->svc->removeClass('.selected', 'selected'); } ... }

Remove the "selected"' class from all elements to clear tab highlighting

WebApps '10 - June 24, 2010 98

slide-99
SLIDE 99

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_1', 'selected'); } ... }

WebApps '10 - June 24, 2010 99

slide-100
SLIDE 100

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_1', 'selected'); } ... }

Add "selected" class to the first tab.

WebApps '10 - June 24, 2010 100

slide-101
SLIDE 101

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_1', 'selected'); $this->svc->html('#content', view('tab1_content')); } ... }

WebApps '10 - June 24, 2010 101

slide-102
SLIDE 102

Example: SVC Controller

<?php class TabsExample extends Controller { function tabbase() { $this->svc->initial(view('tabbase_template')); } function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_1', 'selected'); $this->svc->html('#content', view('tab1_content')); } ... }

Update tab content

WebApps '10 - June 24, 2010 102

slide-103
SLIDE 103

Example: SVC Controller

function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_1', 'selected'); $this->svc->html('#content', view('tab1_content')); } function tab2() { $this->svc->initial('tabbase'); $this->svc->text('title', 'Second tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_2', 'selected'); $this->svc->html('#content', view('tab2_content')); } }

WebApps '10 - June 24, 2010 103

slide-104
SLIDE 104

Example: SVC Controller

function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_1', 'selected'); $this->svc->html('#content', view('tab1_content')); } function tab2() { $this->svc->initial('tabbase'); $this->svc->text('title', 'Second tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_2', 'selected'); $this->svc->html('#content', view('tab2_content')); } }

Update second tab in the same way

WebApps '10 - June 24, 2010 104

slide-105
SLIDE 105

Example: SVC Controller

function tab1() { $this->svc->initial('tabbase'); $this->svc->text('title', 'First tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_1', 'selected'); $this->svc->html('#content', view('tab1_content')); } function tab2() { $this->svc->initial('tabbase'); $this->svc->text('title', 'Second tab page'); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_2', 'selected'); $this->svc->html('#content', view('tab2_content')); } }

Duplicated code! We can factor it out.

WebApps '10 - June 24, 2010 105

slide-106
SLIDE 106

Example: SVC Controller

function tab1() { this->_updateTab('First tab page', 1, 'tab1_content'); } function tab2() { $this->_updateTab('Second tab page', 1, 'tab2_content'); } function _updateTab($title, $num, $content) { $this->svc->initial('tabbase'); $this->svc->text('title', $title); $this->svc->removeClass('.selected', 'selected'); $this->svc->addClass('#tab_' . $num, 'selected'); $this->svc->html('#content', view($content)); } }

WebApps '10 - June 24, 2010 106

slide-107
SLIDE 107

SVC Tabs Example: Done!

  • SVC framework will automatically Ajaxify tab

loads.

  • SVC outputs JSON in response to Ajax requests

– Transformations are applied on client by SVC JS code

  • SVC outputs HTML in response to non-Ajax

requests

– Transformations are applied on server-side by SVC code.

  • No JavaScript needs to be written

WebApps '10 - June 24, 2010 107