forked from BorisMoore/jquery-tmpl
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added back support for the alternative pattern: $(selectorForTemplate…
…).tmpl(data).appendTo(target); Following discussions, I plan to make this the preferred pattern, and probably to remove support for the pattern $(target).append(selectorForTemplate, data); The appendTo pattern is convenient in that the jQuery instance after appending (or inserting before, etc) wraps all the elements that have been inserted into the DOM, so facilitates not having to use the rendered event. It does has some anomalies in behavior, but they are part of existing semantics using appendTo without template: $(A).appendTo(B) will remove A from its current container and move it to B. A subsequent call to $(A).appendTo(C) will then move it from B to C. Similarly, for templates: var R = $(A).tmpl(data) will render the data using template A. R.appendTo(B) will then place the rendered data under B. A subsequent call to R.appendTo(C) will then remove the rendered data from under B and move it to under C. Cleaned up some white space in tmpl.js Removed the newCtxs feature, to simplify implementation for appendTo Introduced support for passing an html string (or a stored template) as template using appendTo patterns: $.tmpl(template, data).appendTo(target); Previously using stored templates (not declared as script blocks) was only possible with the append pattern: $(target).append(template, data); Changed signature of $.tmpl to $.tmpl(tmpl, data, options, parentCtx, domFrag), which is consistent with the signature of the instance method. This required some changes in the implementation of the nested template (composition) feature using the {{tmpl}} tag. (Calling a $ctx.nest() function, which then calls $.tmpl()). Added alternative versions of movie.htm demo to show use of append versus appendTo pattern, and, when using appendTo, how to achieve the same scenarios without using tmplCmd or the rendered event. Replaced the movies sample by a version using appendTo, and not using rendered event at all Replaced other samples by use of appendTo etc. and in basic.html sample, show use of both append and appendTo patterns.
- Loading branch information
1 parent
ff67f46
commit 395b359
Showing
9 changed files
with
1,285 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,352 @@ | ||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
<!-- | ||
This sample illustrates using templates for a more complete and | ||
realistic scenario. | ||
It uses the NetFlix OData JSONP services as a source of data. | ||
This version of the movies sample demo uses the | ||
$( templateSelector ).tmpl( data ).appendTo( targetSelector ) | ||
pattern, and does not use the tmplCmd plugin or the rendered event. | ||
--> | ||
<html xmlns="http://www.w3.org/1999/xhtml"> | ||
<head> | ||
<title>jQuery + OData + Netflix Catalog API</title> | ||
<link href="css/jquery-ui-1.8.1.custom.css" rel="stylesheet" type="text/css" /> | ||
<link href="css/movies.css" rel="stylesheet" type="text/css" /> | ||
</head> | ||
<body> | ||
<div id="about"> | ||
This is a demo of updates to the jQuery templating feature, proposed by Microsoft.<br/> | ||
The source can be viewed here: <a href="http://github.com/nje/jquery-tmpl/">NJE Templating Branch on GitHub</a> | ||
</div> | ||
<div id="pageBody"> | ||
<h1>Netflix: Book a Movie...</h1> | ||
|
||
<ul id="genres"> | ||
<li class="selected">Cartoons</li> | ||
<li>Drama</li> | ||
<li>Foreign</li> | ||
<li>Action Classics</li> | ||
<li>Horror</li> | ||
<li>Sci-Fi Cult Classics</li> | ||
</ul> | ||
|
||
<div id="pager"><ul class="pages"><li class="pgEmpty">first</li><li class="pgEmpty">prev</li></ul></div> | ||
|
||
<div id="movieList"></div> | ||
<table id="bookingsList"> | ||
<tbody><tr class="cart"><td class="cart-false" colspan="4"> | ||
<span class="text">0 items in Cart...</span> | ||
</td></tr></tbody> | ||
</table> | ||
<br/> | ||
</div> | ||
<script src="http://code.jquery.com/jquery.js"></script> | ||
<script src="../../jquery.tmpl.js" type="text/javascript"></script> | ||
<script src="components/jquery.pager.js" type="text/javascript"></script> | ||
<script src="components/jquery-ui-1.8.1.custom.js" type="text/javascript"></script> | ||
|
||
<script id="movieTmpl" type="text/html"> | ||
<div> | ||
<div><img src="${BoxArt.LargeUrl}" /> </div> | ||
<strong>${Name}</strong> | ||
<p>${Synopsis}</p> | ||
<input type="button" title="Buy tickets for '${Name}'" value="Add to cart..." class="buyButton"/> | ||
<br/> | ||
</div> | ||
</script> | ||
|
||
<script id="cartTmpl" type="text/html"> | ||
<td class="cart-${!!count}" colspan="4"> | ||
<span class="text">${count} items in Cart...</span> | ||
{{if count}} | ||
<span id="submit">Checkout</span> | ||
<span id="cancel">Remove All</span> | ||
{{if count>1}} | ||
<span id="sort"><span id="sortBtn">Sort</span>: | ||
<select> | ||
<option value="0" {{if sortBy==="0"}}selected{{/if}}>Name A-Z</option> | ||
<option value="1" {{if sortBy==="1"}}selected{{/if}}>Name Z-A</option> | ||
<option value="2" {{if sortBy==="2"}}selected{{/if}}>Date</option> | ||
</select> | ||
</span> | ||
{{/if}} | ||
</select> | ||
{{/if}} | ||
</td> | ||
</script> | ||
|
||
<script id="bookingTitleTmpl" type="text/html"> | ||
<tr class="bookingTitle${$ctx.mode}"> | ||
<td>${movie.Name}</td><td>${movieTheater}</td> | ||
<td>${formatDate(date)}</td> | ||
<td> | ||
${quantity} | ||
<span class="ui-icon close"></span> | ||
</td> | ||
</tr> | ||
</script> | ||
|
||
<script id="bookingEditTmpl" type="text/html"> | ||
{{tmpl(this.data, {mode: "Edit"}) "#bookingTitleTmpl"}} | ||
<tr class="bookingEdit"> | ||
<td colspan="4"> | ||
<div class="fields"> | ||
<span>Movie Theater: </span><input class="theater" type="text" value="${movieTheater}" /><br/> | ||
<span>Date: </span><input class="date" type="text" value="${formatDate(date)}" /><br/> | ||
<span>Quantity: </span><input class="quantity" type="text" value="${quantity}" /> | ||
</div> | ||
<div><img src="${movie.BoxArt.LargeUrl}" /></div> | ||
</td> | ||
</tr> | ||
</script> | ||
|
||
<script type="text/javascript"> | ||
var genre="Cartoons", pageIndex=1, pageSize=3, pageCount=0, | ||
cart = { bookings: {}, count: 0, sortBy:0 }, bookingCtxs = {}, selectedBooking; | ||
|
||
getMovies( pageIndex ); | ||
|
||
$( "#genres li" ).click( selectGenre ); | ||
|
||
$( ".cart" ) | ||
.delegate( "select", "change", sort ) | ||
.delegate( "#sortBtn", "click", sort ) | ||
.delegate( "#submit", "click", function() { | ||
alert( cart.count + " bookings submitted for payment..."); | ||
removeBookings(); | ||
}) | ||
.delegate( "#cancel", "click", function() { | ||
removeBookings(); | ||
}) | ||
.empty(); | ||
|
||
$( "#cartTmpl" ) | ||
.tmpl( cart ) | ||
.appendTo( ".cart", cart ); | ||
|
||
var cartCtx = $.tmpl( ".cart td" ); | ||
|
||
function selectGenre() { | ||
$( "#genres li" ).removeClass( "selected" ); | ||
$( this ).addClass( "selected" ); | ||
|
||
pageIndex = 1; | ||
genre = encodeURI( $(this).text() ); | ||
getMovies( pageIndex ); | ||
} | ||
|
||
function sort() { | ||
var compare = compareName, reverse = false, data = []; | ||
cart.sortBy = $( "#sort select" ).val(); | ||
switch ( $( "#sort select" ).val() ) { | ||
case "1": | ||
reverse = true; | ||
break; | ||
case "2": | ||
compare = compareDate; | ||
break; | ||
} | ||
|
||
for ( var item in cart.bookings ) { | ||
data.push( cart.bookings[item] ); | ||
} | ||
data = data.sort( compare ); | ||
|
||
for ( var i = 0, l = data.length; i < l; i++ ) { | ||
$( bookingCtxs[data[i].movie.Id].nodes ).appendTo( "#bookingsList" ); | ||
} | ||
|
||
function compareName( a, b ) { | ||
return a == b ? 0 : (((a.movie.Name > b.movie.Name) !== reverse) ? 1 : -1); | ||
} | ||
function compareDate( a, b ) { | ||
return a.date - b.date; | ||
} | ||
} | ||
|
||
function getMovies( index ) { | ||
var query = "http://odata.netflix.com/Catalog/Genres('" + genre + "')/Titles" + | ||
"?$format=json" + | ||
"&$inlinecount=allpages" + // get total number of records | ||
"&$skip=" + (index-1) * pageSize + // skip to first record of page | ||
"&$top=" + pageSize; // page size | ||
|
||
pageIndex = index; | ||
|
||
$( "#movieList" ) | ||
.fadeOut( "medium", function () { | ||
$.ajax({ | ||
dataType: "jsonp", | ||
url: query, | ||
jsonp: "$callback", | ||
success: showMovies | ||
}); | ||
}); | ||
} | ||
|
||
function showMovies( data ) { | ||
pageCount = Math.ceil( data.d.__count/pageSize ), | ||
movies = data.d.results; | ||
|
||
$( "#pager" ).pager({ pagenumber: pageIndex, pagecount: pageCount, buttonClickCallback: getMovies }); | ||
|
||
// show movies in template | ||
$( "#movieList" ).empty(); | ||
|
||
$( "#movieTmpl" ) | ||
.tmpl( movies ) //, { rendered: onMovieRendered } ) | ||
.appendTo( "#movieList" ) | ||
.find( "div" ).fadeIn( 4000 ).end() | ||
.find( ".buyButton" ).click( function() { | ||
buyTickets( $(this).tmpl().data ); | ||
}); | ||
|
||
$( "#movieList" ).fadeIn( "medium" ) | ||
} | ||
|
||
function buyTickets( movie ) { | ||
// Add item to cart | ||
var booking = cart.bookings[movie.Id]; | ||
if ( booking ) { | ||
booking.quantity++; | ||
} else { | ||
cart.count++; | ||
updateContext( cartCtx ); | ||
booking = { movie: movie, date: new Date(), quantity: 1, movieTheater: "" }; | ||
} | ||
selectBooking( booking ); | ||
} | ||
|
||
function selectBooking( booking ) { | ||
if ( selectedBooking ) { | ||
if ( selectedBooking === booking ) { | ||
updateBooking( bookingCtxs[selectedBooking.movie.Id]); | ||
return; | ||
} | ||
// Collapse previously selected booking, and switch to non-edit view | ||
var oldSelected = selectedBooking; | ||
$( "div", bookingCtxs[oldSelected.movie.Id].nodes ).animate( { height: 0 }, 500, function() { | ||
switchView( oldSelected ); | ||
}); | ||
} | ||
selectedBooking = booking; | ||
if ( !booking ) { | ||
return; | ||
} | ||
if ( cart.bookings[booking.movie.Id] ) { | ||
switchView( booking, true ); | ||
} else { | ||
cart.bookings[booking.movie.Id] = booking; | ||
var bookingNode = $( "#bookingEditTmpl" ) | ||
.tmpl( booking, { animate: true } ) | ||
.appendTo( "#bookingsList" ).last()[0]; | ||
|
||
// Attach handlers etc. on the rendered template. | ||
// Pass the template context of the second tr, which the context for the "bookingEditTmpl" template | ||
var newCtx = $.tmpl( bookingNode ); | ||
bookingCtxs[booking.movie.Id] = newCtx; | ||
bookingEditRendered( newCtx ); | ||
} | ||
} | ||
|
||
function bookingEditRendered( ctx ) { | ||
var data = ctx.data, nodes = ctx.nodes; | ||
|
||
$( nodes[0] ).click( function() { | ||
selectBooking(); | ||
}); | ||
|
||
$( ".close", nodes ).click( removeBooking ); | ||
|
||
$( ".date", nodes ).change( function() { | ||
data.date = $(this).datepicker( "getDate" ); | ||
updateBooking( ctx ); | ||
}) | ||
.datepicker({ dateFormat: "DD, d MM, yy" }); | ||
|
||
$( ".quantity", nodes ).change( function() { | ||
data.quantity = $(this).val(); | ||
updateBooking( ctx ); | ||
}); | ||
|
||
$( ".theater", nodes ).change( function() { | ||
data.movieTheater = $(this).val(); | ||
updateBooking( ctx ); | ||
}); | ||
|
||
if ( ctx.animate ) { | ||
$( "div", nodes ).css( "height", 0 ).animate( { height: 116 }, 500 ); | ||
} | ||
} | ||
|
||
function bookingRendered( ctx ) { | ||
$( ctx.nodes ).click( function() { | ||
selectBooking( ctx.data ); | ||
}); | ||
$( ".close", ctx.nodes ).click( removeBooking ); | ||
} | ||
|
||
function switchView( booking, edit ) { | ||
if ( !booking ) { | ||
return; | ||
} | ||
var ctx = bookingCtxs[booking.movie.Id], | ||
tmpl = $.tmpl(edit ? "#bookingEditTmpl" : "#bookingTitleTmpl"); | ||
if ( ctx.tmpl !== tmpl) { | ||
ctx.tmpl = tmpl; | ||
updateContext( ctx ); | ||
(edit ? bookingEditRendered : bookingRendered)( ctx ); | ||
} | ||
} | ||
|
||
function updateBooking( ctx ) { | ||
ctx.animate = false; | ||
updateContext( ctx ); | ||
(ctx.data === selectedBooking ? bookingEditRendered : bookingRendered)( ctx ); | ||
ctx.animate = true; | ||
} | ||
|
||
function removeBooking() { | ||
var booking = $.tmpl(this).data; | ||
if ( booking === selectedBooking ) { | ||
selectedBooking = null; | ||
} | ||
delete cart.bookings[booking.movie.Id]; | ||
cart.count--; | ||
updateContext( cartCtx ); | ||
$( bookingCtxs[booking.movie.Id].nodes ).remove(); | ||
delete bookingCtxs[booking.movie.Id]; | ||
return false; | ||
} | ||
|
||
function removeBookings() { | ||
for ( var ctx in bookingCtxs ) { | ||
$( bookingCtxs[ctx].nodes ).remove(); | ||
delete bookingCtxs[ctx]; | ||
} | ||
bookingCtxs = {}; | ||
cart.count = 0; | ||
cart.bookings = {}; | ||
selectedBooking = null; | ||
updateContext( cartCtx ); | ||
} | ||
|
||
function formatDate( date ) { | ||
return date.toLocaleDateString(); | ||
} | ||
|
||
function updateContext( ctx ) { | ||
var coll = ctx.nodes; | ||
$( coll[0] ).before( ctx); | ||
$( coll ).remove(); | ||
} | ||
|
||
function removeContext( ctx ) { | ||
$( ctx.nodes ).remove(); | ||
} | ||
</script> | ||
|
||
</body> | ||
</html> |
Oops, something went wrong.