Skip to content
This repository was archived by the owner on Jan 10, 2024. It is now read-only.

Commit 611aa9e

Browse files
author
Pat Patterson
committed
Added PhoneGap app
1 parent 87d3e99 commit 611aa9e

File tree

4 files changed

+518
-38
lines changed

4 files changed

+518
-38
lines changed

README.markdown

+82
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,85 @@ Your HTML page will need to include jQuery and the toolkit, then create a client
108108
</html>
109109

110110
More fully featured samples are provided in [example.html](Force.com-JavaScript-REST-Toolkit/blob/master/example.html) and [mobile.html](Force.com-JavaScript-REST-Toolkit/blob/master/mobile.html).
111+
112+
Using the Toolkit in a PhoneGap app
113+
-----------------------------------
114+
115+
Your HTML page will need to include jQuery, the toolkit, PhoneGap and the ChildBrowser plugin, then create a client object, passing a session ID to the constructor. You can use __https://login.salesforce.com/services/oauth2/success__ as the redirect URI and catch the page load in ChildBrowser.
116+
117+
An absolutely minimal sample using OAuth to obtain a session ID is:
118+
119+
<html>
120+
<head>
121+
<script type="text/javascript" src="static/jquery.js"></script>
122+
<script type="text/javascript" src="static/jquery.popup.js"></script>
123+
<script type="text/javascript" src="forcetk.js"></script>
124+
<script type="text/javascript" src="phonegap.0.9.5.min.js"></script>
125+
<script type="text/javascript" src="ChildBrowser.js"></script>
126+
<script type="text/javascript">
127+
// OAuth Configuration
128+
var loginUrl = 'https://login.salesforce.com/';
129+
var clientId = 'YOUR_CLIENT_ID';
130+
var redirectUri = 'https://login.salesforce.com/services/oauth2/success';
131+
132+
// We'll get an instance of the REST API client in a callback
133+
// after we do OAuth
134+
var client = null;
135+
136+
$(document).ready(function() {
137+
var cb = ChildBrowser.install();
138+
$('#login').click(function(e) {
139+
e.preventDefault();
140+
cb.onLocationChange = function(loc){
141+
if (loc.startsWith(redirectUri)) {
142+
cb.close();
143+
sessionCallback(unescape(loc));
144+
}
145+
};
146+
cb.showWebPage(getAuthorizeUrl(loginUrl, clientId, redirectUri));
147+
});
148+
});
149+
150+
function getAuthorizeUrl(loginUrl, clientId, redirectUri){
151+
return loginUrl+'services/oauth2/authorize?display=touch'
152+
+'&response_type=token&client_id='+escape(clientId)
153+
+'&redirect_uri='+escape(redirectUri);
154+
}
155+
156+
function sessionCallback(loc) {
157+
var oauthResponse = {};
158+
159+
var fragment = loc.split("#")[1];
160+
161+
if (fragment) {
162+
var nvps = fragment.split('&');
163+
for (var nvp in nvps) {
164+
var parts = nvps[nvp].split('=');
165+
oauthResponse[parts[0]] = unescape(parts[1]);
166+
}
167+
}
168+
169+
if (typeof oauthResponse === 'undefined'
170+
|| typeof oauthResponse['access_token'] === 'undefined') {
171+
errorCallback({
172+
status: 0,
173+
statusText: 'Unauthorized',
174+
responseText: 'No OAuth response'
175+
});
176+
} else {
177+
client = new forcetk.Client(oauthResponse.access_token, null, oauthResponse.instance_url);
178+
179+
client.query("SELECT Name FROM Account LIMIT 1",
180+
function(response){
181+
$('#message').html('The first account I see is '
182+
+response.records[0].Name);
183+
}
184+
);
185+
}
186+
}
187+
</script>
188+
<p id="message">Click here.</p>
189+
</html>
190+
191+
A fully featured sample is provided in [phonegap.html](Force.com-JavaScript-REST-Toolkit/blob/master/phonegap.html).
192+

forcetk.js

+60-38
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ if (forcetk.Client === undefined) {
4444
if (window.$j === undefined) {
4545
$j = $;
4646
}
47-
47+
4848
/**
4949
* The Client provides a convenient wrapper for the Force.com REST API,
5050
* allowing JavaScript in Visualforce pages to use the API via the Ajax
@@ -68,37 +68,48 @@ if (forcetk.Client === undefined) {
6868
} else {
6969
this.instance_url = instanceUrl;
7070
}
71-
if (typeof proxyUrl === 'undefined' || proxyUrl == null) {
72-
this.proxy_url = location.protocol + "//" + location.hostname
73-
+ "/services/proxy";
71+
if (typeof proxyUrl === 'undefined' || proxyUrl === null) {
72+
if (location.protocol === 'file:'){
73+
// In PhoneGap
74+
this.proxy_url = null;
75+
} else {
76+
// In Visualforce
77+
this.proxy_url = location.protocol + "//" + location.hostname
78+
+ "/services/proxy";
79+
}
7480
} else {
81+
// On a server outside VF
7582
this.proxy_url = proxyUrl;
7683
}
7784
}
7885

7986
/*
80-
* Low level utility function to call the Salesforce proxy endpoint.
87+
* Low level utility function to call the Salesforce endpoint.
8188
* @param path resource path relative to /services/data
8289
* @param callback function to which response will be passed
90+
* @param [error=null] function to which jqXHR will be passed in case of error
8391
* @param [method="GET"] HTTP method for call
8492
* @param [payload=null] payload for POST/PATCH etc
8593
*/
86-
forcetk.Client.prototype.proxyAjax = function(path, callback, method, payload) {
94+
forcetk.Client.prototype.ajax = function(path, callback, error, method, payload) {
8795
var url = this.instance_url + '/services/data' + path;
8896
var sessionId = this.sessionId;
8997

9098
$j.ajax({
9199
type: (typeof method === 'undefined' || method == null)
92100
? "GET" : method,
93-
url: this.proxy_url,
101+
url: (this.proxy_url !== null) ? this.proxy_url : url,
94102
contentType: 'application/json',
95103
processData: false,
96104
data: (typeof payload === 'undefined' || payload == null)
97105
? null : payload,
98106
success: callback,
107+
error: error,
99108
dataType: "json",
100109
beforeSend: function(xhr) {
101-
xhr.setRequestHeader('SalesforceProxy-Endpoint', url);
110+
if (this.proxy_url !== null) {
111+
xhr.setRequestHeader('SalesforceProxy-Endpoint', url);
112+
}
102113
xhr.setRequestHeader("Authorization", "OAuth " + sessionId);
103114
}
104115
});
@@ -109,48 +120,53 @@ if (forcetk.Client === undefined) {
109120
* available, including the version, label, and a link to each version's
110121
* root.
111122
* @param callback function to which response will be passed
123+
* @param [error=null] function to which jqXHR will be passed in case of error
112124
*/
113-
forcetk.Client.prototype.versions = function(callback) {
114-
this.proxyAjax('/', callback);
125+
forcetk.Client.prototype.versions = function(callback, error) {
126+
this.ajax('/', callback, error);
115127
}
116128

117129
/*
118130
* Lists available resources for the client's API version, including
119131
* resource name and URI.
120132
* @param callback function to which response will be passed
133+
* @param [error=null] function to which jqXHR will be passed in case of error
121134
*/
122-
forcetk.Client.prototype.resources = function(callback) {
123-
this.proxyAjax('/' + this.apiVersion + '/', callback);
135+
forcetk.Client.prototype.resources = function(callback, error) {
136+
this.ajax('/' + this.apiVersion + '/', callback, error);
124137
}
125138

126139
/*
127140
* Lists the available objects and their metadata for your organization's
128141
* data.
129142
* @param callback function to which response will be passed
143+
* @param [error=null] function to which jqXHR will be passed in case of error
130144
*/
131-
forcetk.Client.prototype.describeGlobal = function(callback) {
132-
this.proxyAjax('/' + this.apiVersion + '/sobjects/', callback);
145+
forcetk.Client.prototype.describeGlobal = function(callback, error) {
146+
this.ajax('/' + this.apiVersion + '/sobjects/', callback, error);
133147
}
134148

135149
/*
136150
* Describes the individual metadata for the specified object.
137151
* @param objtype object type; e.g. "Account"
138152
* @param callback function to which response will be passed
153+
* @param [error=null] function to which jqXHR will be passed in case of error
139154
*/
140-
forcetk.Client.prototype.metadata = function(objtype, callback) {
141-
this.proxyAjax('/' + this.apiVersion + '/sobjects/' + objtype + '/'
142-
, callback);
155+
forcetk.Client.prototype.metadata = function(objtype, callback, error) {
156+
this.ajax('/' + this.apiVersion + '/sobjects/' + objtype + '/'
157+
, callback, error);
143158
}
144159

145160
/*
146161
* Completely describes the individual metadata at all levels for the
147162
* specified object.
148163
* @param objtype object type; e.g. "Account"
149164
* @param callback function to which response will be passed
165+
* @param [error=null] function to which jqXHR will be passed in case of error
150166
*/
151-
forcetk.Client.prototype.describe = function(objtype, callback) {
152-
this.proxyAjax('/' + this.apiVersion + '/sobjects/' + objtype
153-
+ '/describe/', callback);
167+
forcetk.Client.prototype.describe = function(objtype, callback, error) {
168+
this.ajax('/' + this.apiVersion + '/sobjects/' + objtype
169+
+ '/describe/', callback, error);
154170
}
155171

156172
/*
@@ -160,10 +176,11 @@ if (forcetk.Client === undefined) {
160176
* the record, e.g. {:Name "salesforce.com", :TickerSymbol
161177
* "CRM"}
162178
* @param callback function to which response will be passed
179+
* @param [error=null] function to which jqXHR will be passed in case of error
163180
*/
164-
forcetk.Client.prototype.create = function(objtype, fields, callback) {
165-
this.proxyAjax('/' + this.apiVersion + '/sobjects/' + objtype + '/'
166-
, callback, "POST", JSON.stringify(fields));
181+
forcetk.Client.prototype.create = function(objtype, fields, callback, error) {
182+
this.ajax('/' + this.apiVersion + '/sobjects/' + objtype + '/'
183+
, callback, error, "POST", JSON.stringify(fields));
167184
}
168185

169186
/*
@@ -173,10 +190,11 @@ if (forcetk.Client === undefined) {
173190
* @param fields comma-separated list of fields for which to return
174191
* values; e.g. Name,Industry,TickerSymbol
175192
* @param callback function to which response will be passed
193+
* @param [error=null] function to which jqXHR will be passed in case of error
176194
*/
177-
forcetk.Client.prototype.retrieve = function(objtype, id, fieldlist, callback) {
178-
this.proxyAjax('/' + this.apiVersion + '/sobjects/' + objtype + '/' + id
179-
+ '?fields=' + fieldlist, callback);
195+
forcetk.Client.prototype.retrieve = function(objtype, id, fieldlist, callback, error) {
196+
this.ajax('/' + this.apiVersion + '/sobjects/' + objtype + '/' + id
197+
+ '?fields=' + fieldlist, callback, error);
180198
}
181199

182200
/*
@@ -187,10 +205,11 @@ if (forcetk.Client === undefined) {
187205
* the record, e.g. {:Name "salesforce.com", :TickerSymbol
188206
* "CRM"}
189207
* @param callback function to which response will be passed
208+
* @param [error=null] function to which jqXHR will be passed in case of error
190209
*/
191-
forcetk.Client.prototype.update = function(objtype, id, fields, callback) {
192-
this.proxyAjax('/' + this.apiVersion + '/sobjects/' + objtype + '/' + id
193-
, callback, "PATCH", JSON.stringify(fields));
210+
forcetk.Client.prototype.update = function(objtype, id, fields, callback, error) {
211+
this.ajax('/' + this.apiVersion + '/sobjects/' + objtype + '/' + id
212+
, callback, error, "PATCH", JSON.stringify(fields));
194213
}
195214

196215
/*
@@ -199,31 +218,34 @@ if (forcetk.Client === undefined) {
199218
* @param objtype object type; e.g. "Account"
200219
* @param id the record's object ID
201220
* @param callback function to which response will be passed
221+
* @param [error=null] function to which jqXHR will be passed in case of error
202222
*/
203-
forcetk.Client.prototype.del = function(objtype, id, callback) {
204-
this.proxyAjax('/' + this.apiVersion + '/sobjects/' + objtype + '/' + id
205-
, callback, "DELETE");
223+
forcetk.Client.prototype.del = function(objtype, id, callback, error) {
224+
this.ajax('/' + this.apiVersion + '/sobjects/' + objtype + '/' + id
225+
, callback, error, "DELETE");
206226
}
207227

208228
/*
209229
* Executes the specified SOQL query.
210230
* @param soql a string containing the query to execute - e.g. "SELECT Id,
211231
* Name from Account ORDER BY Name LIMIT 20"
212232
* @param callback function to which response will be passed
233+
* @param [error=null] function to which jqXHR will be passed in case of error
213234
*/
214-
forcetk.Client.prototype.query = function(soql, callback) {
215-
this.proxyAjax('/' + this.apiVersion + '/query?q=' + escape(soql)
216-
, callback);
235+
forcetk.Client.prototype.query = function(soql, callback, error) {
236+
this.ajax('/' + this.apiVersion + '/query?q=' + escape(soql)
237+
, callback, error);
217238
}
218239

219240
/*
220241
* Executes the specified SOSL search.
221242
* @param sosl a string containing the search to execute - e.g. "FIND
222243
* {needle}"
223244
* @param callback function to which response will be passed
245+
* @param [error=null] function to which jqXHR will be passed in case of error
224246
*/
225-
forcetk.Client.prototype.search = function(sosl, callback) {
226-
this.proxyAjax('/' + this.apiVersion + '/search?s=' + escape(sosl)
227-
, callback);
247+
forcetk.Client.prototype.search = function(sosl, callback, error) {
248+
this.ajax('/' + this.apiVersion + '/search?s=' + escape(sosl)
249+
, callback, error);
228250
}
229251
}

0 commit comments

Comments
 (0)