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

Commit 348e249

Browse files
author
Pat Patterson
committed
Updated forcetk.js to work with proxy, added proxy, refactored sample to suit
1 parent 1e27f99 commit 348e249

12 files changed

+1336
-249
lines changed

README.markdown

+64-4
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ Visualforce hosts with an endpoint of the form https://abc.na1.visual.force.com/
1414
Dependencies
1515
------------
1616

17-
The toolkit uses jQuery. It has been tested on jQuery 1.4.4, but other versions may also work.
17+
The toolkit uses [jQuery](http://jquery.com/). It has been tested on jQuery 1.4.4, but other versions may also work.
1818

1919
Configuration
2020
-------------
2121

2222
You must add the correct REST endpoint hostname for your instance (i.e. https://na1.salesforce.com/ or similar) as a remote site in *Your Name > Administration Setup > Security Controls > Remote Site Settings*.
2323

24-
Using the Toolkit
25-
-----------------
24+
Using the Toolkit in a Visualforce page
25+
---------------------------------------
2626

27-
Create a zip file containing forcetk.js, jquery.js, and any other static resources your project may need. Upload the zip via *Your Name > App Setup > Develop > Static Resources*.
27+
Create a zip file containing app.js, forcetk.js, jquery.js, and any other static resources your project may need. Upload the zip via *Your Name > App Setup > Develop > Static Resources*.
2828

2929
Your Visualforce page will need to include jQuery and the toolkit, then create a client object, passing a session ID to the constructor. An absolutely minimal sample is:
3030

@@ -46,3 +46,63 @@ Your Visualforce page will need to include jQuery and the toolkit, then create a
4646
</apex:page>
4747

4848
More fully featured samples are provided in [example.page](https://github.com/metadaddy/Force.com-JavaScript-REST-Toolkit/blob/master/example.page) and [mobile.page](https://github.com/metadaddy/Force.com-JavaScript-REST-Toolkit/blob/master/mobile.page). [Watch a brief demo of the samples](http://www.youtube.com/watch?v=qNA8nxfPgBU).
49+
50+
Using the Toolkit in an HTML page outside the Force.com platform
51+
----------------------------------------------------------------
52+
53+
You will need to deploy proxy.php to your server, configuring CORS support (see comments in proxy.php) if your JavaScript is to be hosted on a different server.
54+
55+
Your HTML page will need to include jQuery and the toolkit, then create a client object, passing a session ID to the constructor. An absolutely minimal sample using OAuth to obtain a session ID is:
56+
57+
<html>
58+
<head>
59+
<script type="text/javascript" src="static/jquery.js"></script>
60+
<script type="text/javascript" src="static/jquery.popup.js"></script>
61+
<script type="text/javascript" src="forcetk.js"></script>
62+
<script type="text/javascript">
63+
// OAuth Configuration
64+
var loginUrl = 'https://login.salesforce.com/';
65+
var clientId = 'YOUR_CLIENT_ID';
66+
var redirectUri = 'PATH_TO_YOUR_APP/oauthcallback.html';
67+
var proxyUrl = 'PATH_TO_YOUR_APP/proxy.php?mode=native';
68+
69+
// We'll get an instance of the REST API client in a callback
70+
// after we do OAuth
71+
var client = null;
72+
73+
$(document).ready(function() {
74+
$('#message').popupWindow({
75+
windowURL: getAuthorizeUrl(loginUrl, clientId, redirectUri),
76+
windowName: 'Connect',
77+
centerBrowser: 1,
78+
height:524,
79+
width:675
80+
});
81+
});
82+
83+
function getAuthorizeUrl(loginUrl, clientId, redirectUri){
84+
return loginUrl+'services/oauth2/authorize?display=popup'
85+
+'&response_type=token&client_id='+escape(clientId)
86+
+'&redirect_uri='+escape(redirectUri);
87+
}
88+
89+
function sessionCallback(oauthResponse) {
90+
if (typeof oauthResponse === 'undefined'
91+
|| typeof oauthResponse['access_token'] === 'undefined') {
92+
$('#message').html('Error - unauthorized!');
93+
} else {
94+
client = new forcetk.Client(oauthResponse.access_token,
95+
null, oauthResponse.instance_url, proxyUrl);
96+
97+
client.query("SELECT Name FROM Account LIMIT 1",
98+
function(response){
99+
$('#message').html('The first account I see is '
100+
+response.records[0].Name);
101+
});
102+
}
103+
}
104+
</script>
105+
<p id="message">Click here.</p>
106+
</html>
107+
108+
More fully featured samples are provided in [example.html](https://github.com/metadaddy/Force.com-JavaScript-REST-Toolkit/blob/master/example.html) and [mobile.html](https://github.com/metadaddy/Force.com-JavaScript-REST-Toolkit/blob/master/mobile.html).

ajax.gif

723 Bytes
Loading

app.js

+243
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/*
2+
* Copyright (c) 2011, salesforce.com, inc.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
6+
* that the following conditions are met:
7+
*
8+
* Redistributions of source code must retain the above copyright notice, this list of conditions and the
9+
* following disclaimer.
10+
*
11+
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
12+
* the following disclaimer in the documentation and/or other materials provided with the distribution.
13+
*
14+
* Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
15+
* promote products derived from this software without specific prior written permission.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
18+
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19+
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21+
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24+
* POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
/*
28+
* This is a simple jQuery-based app that uses the Force.com REST API.
29+
* See vf.js for code required to run this in Visualforce
30+
* See custom.js for code required to run this on your own server
31+
*/
32+
33+
function logout(e) {
34+
e.preventDefault();
35+
36+
window.location.href = 'https://login.salesforce.com/secur/logout.jsp';
37+
}
38+
39+
function errorCallback(jqXHR){
40+
$dialog.dialog('option', 'title', 'Error');
41+
$dialog.dialog('option', 'modal', true);
42+
$dialog.html(TrimPath.processDOMTemplate("error_jst", jqXHR));
43+
$dialog.find('#ok').click(function(e) {
44+
e.preventDefault();
45+
$dialog.dialog('close');
46+
logout(e);
47+
});
48+
$dialog.dialog('open');
49+
}
50+
51+
function metadataCallback(response){
52+
// Using TrimPath Template for now - may switch to jQuery Template at some
53+
// point
54+
$j('#prompt').html(TrimPath.processDOMTemplate("prompt_jst"
55+
, response));
56+
57+
// Set up autocomplete
58+
$j( "#value" ).autocomplete({
59+
source: function( request, response ) {
60+
var query = "SELECT Id, Name FROM Account "+
61+
"WHERE "+$j("#field").val()+" LIKE '%"+request.term+"%' "+
62+
"ORDER BY Name LIMIT 20";
63+
64+
client.query(query, function( data ) {
65+
response( $j.map( data.records, function( record ) {
66+
return {
67+
label: record.Name,
68+
value: record.Id
69+
}
70+
}));
71+
});
72+
},
73+
minLength: 2,
74+
delay: 1000,
75+
select: function( event, ui ) {
76+
if ( ui.item != null ) {
77+
showAccountDetail(ui.item.value);
78+
} else {
79+
filterAccounts($j("#field").val(),this.value);
80+
}
81+
82+
return false;
83+
},
84+
});
85+
86+
$j('#go').click(function(e) {
87+
var field = $j("#field").val();
88+
var value = $j("#value").val();
89+
90+
e.preventDefault();
91+
filterAccounts(field,value);
92+
});
93+
94+
$j('#new').click(function(e) {
95+
e.preventDefault();
96+
97+
// Just make Trimpath happy
98+
var dummy = {};
99+
var i;
100+
for (i = 0; i < response.fields.length; i++) {
101+
dummy[response.fields[i].name] = '';
102+
}
103+
$dialog.html(TrimPath.processDOMTemplate("edit_jst", dummy));
104+
$dialog.find('#action').html('Create').click(function(e) {
105+
e.preventDefault();
106+
$dialog.dialog('close');
107+
108+
var fields = {};
109+
$dialog.find('input').each(function() {
110+
var child = $j(this);
111+
if ( child.val().length > 0 ) {
112+
fields[child.attr("name")] = child.val();
113+
}
114+
});
115+
116+
$j('#list').html(ajaxgif+" creating account...");
117+
118+
client.create('Account', fields, createCallback);
119+
});
120+
$dialog.dialog('option', 'title', 'New Account');
121+
$dialog.dialog('open');
122+
});
123+
124+
filterAccounts();
125+
}
126+
127+
function queryCallback(response) {
128+
$j('#list').html(TrimPath.processDOMTemplate("accounts_jst"
129+
, response));
130+
131+
$j('#version').html($j.fn.jquery);
132+
$j('#uiversion').html($j.ui.version);
133+
134+
$j("#list tr:nth-child(odd)").addClass("odd");
135+
136+
$j('#logout').click(logout);
137+
138+
$j('#accounts').find('.id')
139+
.hover(function() {
140+
$j(this).addClass("highlighted");
141+
},function(){
142+
$j(this).removeClass("highlighted");
143+
})
144+
.click(function(){
145+
showAccountDetail(this.id);
146+
});
147+
}
148+
149+
// Make our own startsWith utility fn
150+
String.prototype.startsWith = function(str){
151+
return (this.substr(0, str.length) === str);
152+
}
153+
154+
function detailCallback(response) {
155+
if (response.Website != null
156+
&& !response.Website.startsWith('http://')) {
157+
response.Website = 'http://'+response.Website;
158+
}
159+
$dialog.html(TrimPath.processDOMTemplate("detail_jst"
160+
,response));
161+
$dialog.find('#industry').click(function(e) {
162+
e.preventDefault();
163+
$dialog.dialog('close');
164+
filterIndustry($j(this).html());
165+
});
166+
$dialog.find('#delete').click(function(e) {
167+
e.preventDefault();
168+
$dialog.dialog('close');
169+
$j('#list').html(ajaxgif+" deleting account...");
170+
client.del('Account', $dialog.find('#id').val(), deleteCallback);
171+
});
172+
$dialog.find('#edit').click(function(e) {
173+
e.preventDefault();
174+
$dialog.html(TrimPath.processDOMTemplate("edit_jst"
175+
,response));
176+
$dialog.find('#action').html('Update').click(function(e) {
177+
e.preventDefault();
178+
$dialog.dialog('close');
179+
180+
var fields = {};
181+
$dialog.find('input').each(function() {
182+
var child = $j(this);
183+
if ( child.val().length > 0 && child.attr("name") != 'id') {
184+
fields[child.attr("name")] = child.val();
185+
}
186+
});
187+
188+
$j('#list').html(ajaxgif+" updating account...");
189+
190+
client.update('Account', $dialog.find('#id').val(), fields, updateCallback);
191+
});
192+
});
193+
}
194+
195+
function createCallback(response) {
196+
$j('#list').html('Created '+response.id);
197+
198+
setTimeout("filterAccounts()",1000);
199+
}
200+
201+
function updateCallback(response) {
202+
$j('#list').html('Updated');
203+
204+
setTimeout("filterAccounts()",1000);
205+
}
206+
207+
function deleteCallback(response) {
208+
$j('#list').html('Deleted');
209+
210+
setTimeout("filterAccounts()",1000);
211+
}
212+
213+
function showAccountDetail(id) {
214+
// Show the dialog
215+
$dialog.dialog('option', 'title', 'Account Detail');
216+
$dialog.dialog('open');
217+
$dialog.html(ajaxgif+" retrieving...");
218+
219+
// Get account details and populate the dialog
220+
client.retrieve('Account', id, 'Name,Industry,TickerSymbol,Website'
221+
, detailCallback);
222+
}
223+
224+
function filterIndustry(industry) {
225+
$j('#list').html(ajaxgif+" loading data...");
226+
227+
var query = "SELECT Id, Name FROM Account WHERE Industry = '"+industry
228+
+"' ORDER BY Name LIMIT 20";
229+
230+
client.query(query, queryCallback);
231+
}
232+
233+
function filterAccounts(field, value) {
234+
$j('#list').html(ajaxgif+" loading data...");
235+
236+
var query = ( typeof value !== 'undefined' && value.length > 0 )
237+
? "SELECT Id, Name FROM Account WHERE "+field+" LIKE '%"+value
238+
+"%' ORDER BY Name LIMIT 20"
239+
: "SELECT Id, Name FROM Account ORDER BY Name LIMIT 20";
240+
241+
client.query(query, queryCallback);
242+
}
243+

0 commit comments

Comments
 (0)