<apex:page docType="html-5.0" standardStylesheets="false" showHeader="false" sidebar="false">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Contacts in Backbone.js</title>
<!-- ========= -->
<!-- CSS -->
<!-- ========= -->
<link href="{!URLFOR($Resource.MobileSample_Resources_Backbone, 'resources/css/jquery.mobile-1.3.0.min.css')}" rel="stylesheet" />
<!-- ========= -->
<!-- Libraries -->
<!-- ========= -->
<script src="{!URLFOR($Resource.MobileSample_Resources_Backbone, 'resources/lib/jquery-2.0.0.min.js')}" type="text/javascript"></script>
<script src="{!URLFOR($Resource.MobileSample_Resources_Backbone, 'resources/lib/underscore-1.4.4.min.js')}" type="text/javascript"></script>
<script src="{!URLFOR($Resource.MobileSample_Resources_Backbone, 'resources/lib/backbone-1.0.0.min.js')}" type="text/javascript"></script>
<script src="{!URLFOR($Resource.MobileSample_Resources_Backbone, 'resources/lib/forcetk.js')}" type="text/javascript"></script>
<script src="{!URLFOR($Resource.MobileSample_Resources_Backbone, 'resources/lib/force.entity.js')}" type="text/javascript"></script>
<script>
$( document ).on( "mobileinit",
// Set up the "mobileinit" handler before including jQuery Mobile
function() {
$.mobile.ajaxEnabled = false;
$.mobile.linkBindingEnabled = false;
}
)
</script>
<script src="{!URLFOR($Resource.MobileSample_Resources_Backbone, 'resources/lib/jquerymobile.js')}" type="text/javascript"></script>
</head>
<body>
<!-- ========= -->
<!-- HTML CODE -->
<!-- ========= -->
<div id="contacts" data-role="page" data-title="Contacts">
<div data-role="header">
<h1>Contacts</h1>
</div><!-- /header -->
<div data-role="content" id="contacts-content">
</div>
</div>
<div id="contact" data-role="page" data-title="Contact">
<div data-role="header">
<a href='#' id="back" class='ui-btn-left' data-icon='arrow-l'>Back</a>
<h1>Contact</h1>
</div><!-- /header -->
<div data-role="content" id="contact-content">
</div>
</div>
<!-- ========= -->
<!-- Templates -->
<!-- ========= -->
<script type="text/template" id="contacts-template">
<form>
<button data-role="button" class="new">New Contact</button>
</form>
<ul data-role="listview" data-inset="true" id="contact-list">
</ul>
<div data-role="footer">
<div data-role="fieldcontain">
<label for="select-theme" class="select">UI Theme:</label>
<select class="theme-selector" name="select-theme" id="select-theme">
<option value="default">default</option>
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
<option value="d">dr</option>
<option value="e">e</option>
</select>
</div>
</div>
</script>
<script type="text/template" id="contact-template">
<% if (typeof(Id) !== 'undefined') { %>
<a href="#<%= Id %>"><%- Name %></a>
<% } else { %>
<%- Name %>
<% } %>
</script>
<script type="text/template" id="contact-detail-template">
<form name="contactform" id="contactform">
<% if (typeof(Id) !== 'undefined') { %>
<input type="hidden" name="Id" id="Id" value="<%- Id %>" />
<% } %>
<div data-role="fieldcontain">
<label for="Name">First Name:</label>
<% if (typeof(FirstName) !== 'undefined') { %>
<input name="FirstName" id="FirstName" value="<%- FirstName %>" />
<% } else { %>
<input name="FirstName" id="FirstName" />
<% } %>
</div>
<div data-role="fieldcontain">
<label for="Name">Last Name:</label>
<% if (typeof(LastName) !== 'undefined') { %>
<input name="LastName" id="LastName" value="<%- LastName %>" />
<% } else { %>
<input name="LastName" id="LastName" />
<% } %>
</div>
<div data-role="fieldcontain">
<label for="Email">Email:</label>
<% if (typeof(Email) !== 'undefined') { %>
<input name="Email" id="Email" value="<%- Email %>" />
<% } else { %>
<input name="Email" id="Email" />
<% } %>
</div>
<button data-role="button" data-icon="check" data-inline="true" data-theme="b" class="save">Save</button>
<% if (typeof(Id) !== 'undefined') { %>
<button data-role="button" data-icon="delete" data-inline="true" class="destroy">Delete</button>
<% } %>
</form>
</script>
<!-- =============== -->
<!-- Javascript code -->
<!-- =============== -->
<script type="text/javascript">
function changeTheme(theme){
var hfTheme = theme,
cTheme = theme;
if (theme === 'default') {
// "If no theme swatch letter is set at all, the framework uses the
// "a" swatch (black in the default theme) for headers and footers
// and the "c" swatch (light gray in the default theme) for the page
// content to maximize contrast between the both."
// http://jquerymobile.com/demos/1.2.1/docs/api/themes.html
hfTheme = "a";
cTheme = "c";
}
$.mobile.activePage.find('.ui-btn').not('.ui-li-divider')
.removeClass('ui-btn-up-a ui-btn-up-b ui-btn-up-c ui-btn-up-d ui-btn-up-e ui-btn-hover-a ui-btn-hover-b ui-btn-hover-c ui-btn-hover-d ui-btn-hover-e')
.addClass('ui-btn-up-' + cTheme)
.attr('data-theme', cTheme);
$.mobile.activePage.find('.ui-li-divider').each(function (index, obj) {
if ($(this).parent().attr('data-divider-theme') == 'undefined') {
$(this).removeClass('ui-bar-a ui-bar-b ui-bar-c ui-bar-d ui-bar-e')
.addClass('ui-bar-' + cTheme)
.attr('data-theme', cTheme);
}
})
$.mobile.activePage.find('.ui-header, .ui-footer')
.removeClass('ui-bar-a ui-bar-b ui-bar-c ui-bar-d ui-bar-e')
.addClass('ui-bar-' + hfTheme)
.attr('data-theme', hfTheme);
$.mobile.activePage.removeClass('ui-body-a ui-body-b ui-body-c ui-body-d ui-body-e')
.addClass('ui-body-' + cTheme)
.attr('data-theme', cTheme);
}
$(document).ready(function() {
var creds = {
accessToken: '{!$Api.Session_ID}'
};
Force.init(creds);
myapp();
});
function myapp() {
var app = {}; // create namespace for our app
//--------------
// Models
//--------------
app.Contact = Force.SObject.extend({
sobjectType:'Contact',
fieldlist:['Id', 'FirstName', 'LastName', 'Email']
});
//--------------
// Collections
//--------------
app.ContactsCollection = Force.SObjectCollection.extend({
model: app.Contact,
fieldlist:['Id', 'Name', 'FirstName', 'LastName', 'Email'],
config: function() {
return {type:"soql", query:"SELECT " + this.fieldlist.join(",") + " FROM Contact ORDER BY Name LIMIT 25"};
}
}),
//--------------
// Views
//--------------
// renders individual Contact list item (li)
app.ContactView = Backbone.View.extend({
tagName: 'li',
template: _.template($('#contact-template').html()),
render: function(){
this.$el.html(this.template(this.model.toJSON()));
return this; // enable chained calls
},
initialize: function(){
}
});
// renders individual Contact for editing
app.ContactDetailView = Backbone.View.extend({
template: _.template($('#contact-detail-template').html()),
render: function(){
this.$el.html(this.template(this.model.toJSON()));
return this; // enable chained calls
},
initialize: function(){
this.model.on('destroy', this.remove, this);
this.render();
},
events: {
'change' : 'change',
'click .save' : 'save',
'click .destroy': 'destroy'
},
change: function (event) {
// Apply the change to the model
var target = event.target;
var change = {};
change[target.name] = target.value;
this.model.set(change);
},
save: function(){
this.model.save(null, {
success: function(model) {
app.router.navigate('contacts', {trigger: true});
},
error: function () {
alert('Error saving');
}
});
return false;
},
destroy: function(){
this.model.destroy({
success: function() {
app.router.navigate('contacts', {trigger: true});
},
error: function () {
alert('Error deleting');
}
});
return false;
}
});
// renders the full list of Contacts calling ContactView for each one.
app.ContactsView = Backbone.View.extend({
template: _.template($('#contacts-template').html()),
initialize: function() {
this.render();
this.model.on('add', this.render, this);
this.model.on('reset', this.render, this);
},
events: {
'click .new' : 'newContact',
'change .theme-selector' : 'changeTheme'
},
renderOne: function(contact){
var view = new app.ContactView({model: contact});
this.$('#contact-list').append(view.render().el);
},
render: function(){
this.$el.html(this.template());
this.$('#contact-list').empty();
for (var i = 0, l = this.model.models.length; i < l; i++) {
this.renderOne(this.model.models[i]);
}
},
changeTheme: function(event){
event.preventDefault();
var theme = $(event.target).children("option").filter(":selected").text();
changeTheme(theme);
},
newContact: function(){
app.router.navigate('/new', true);
return false;
}
});
//Define the Application Router
app.Router = Backbone.Router.extend({
routes: {
"": "contacts",
"contacts":"contacts",
"new": "newContact",
":id": "contact"
},
contacts: function() {
var contactsCollection = new app.ContactsCollection();
$.mobile.loading( "show", { text: 'Loading Contacts', textVisible: true } );
contactsCollection.fetch({success: function(){
$.mobile.loading( "hide" );
$("#contacts-content").html(new app.ContactsView({model: contactsCollection}).el);
// Let jQuery Mobile do its stuff
$("#contacts-content").trigger( 'create' );
$.mobile.changePage( "#contacts" , { reverse: false, changeHash: false } );
}});
},
contact: function(id) {
var contact = new app.Contact({Id: id});
$.mobile.loading( "show", { text: 'Loading Contact', textVisible: true } );
contact.fetch({success: function(){
$.mobile.loading( "hide" );
$("#contact-content").html(new app.ContactDetailView({model: contact}).el);
$("#contact-content").trigger( 'create' );
$.mobile.changePage( "#contact" , { reverse: false, changeHash: false } );
}});
},
newContact: function(id) {
var contact = new app.Contact();
$("#contact-content").empty();
$("#contact-content").html(new app.ContactDetailView({model: contact}).el);
$("#contact-content").trigger( 'create' );
$.mobile.changePage( "#contact" , { reverse: false, changeHash: false } );
}
});
app.router = new app.Router();
Backbone.history.start();
}
</script>
</body>
</apex:page>