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

Commit 774a837

Browse files
author
Pat Patterson
committed
Added RemoteTK
1 parent 026cfcc commit 774a837

File tree

4 files changed

+610
-7
lines changed

4 files changed

+610
-7
lines changed

README.markdown

+38-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
Force.com JavaScript REST Toolkit
22
=================================
33

4-
This minimal toolkit allows JavaScript in Visualforce pages to call the Force.com REST API either via the Ajax Proxy (in the case of web apps) or directly (from a PhoneGap app), providing an easy-to-use JavaScript wrapper.
4+
This minimal toolkit allows JavaScript in Visualforce pages to call the Force.com REST API in a number of different ways.
55

66
Background
77
----------
88

99
Due to the [same origin policy](http://en.wikipedia.org/wiki/Same_origin_policy), JavaScript running in Visualforce pages may not use [XmlHttpRequest](http://en.wikipedia.org/wiki/XMLHttpRequest) to directly invoke the REST API, since Visualforce pages have hostnames of the form abc.na1.visual.force.com, and the REST API endpoints are of the form na1.salesforce.com.
1010

11-
We can work around this restriction by using the [AJAX Proxy](http://www.salesforce.com/us/developer/docs/ajax/Content/sforce_api_ajax_queryresultiterator.htm#ajax_proxy). Since the AJAX proxy is present on all
12-
Visualforce hosts with an endpoint of the form https://abc.na1.visual.force.com/services/proxy, our Visualforce-hosted JavaScript can invoke it, passing the desired resource URL in an HTTP header.
11+
The RemoteTK Visualforce Component (comprising RemoteTK.component and RemoteTKController.cls) provides an abstraction very similar to the REST API, implemented via `@RemoteAction` methods in the component's controller. The advantage of this mechanism is that no API calls are consumed. A disadvantage is that upsert is not currently implemented.
1312

14-
Alternatively, to host JavaScript outside the Force.com platform, we can deploy a simple PHP proxy to perform the same function as the AJAX proxy.
13+
Alternatively, the ForceTK JavaScript library works around the same origin restriction by using the [AJAX Proxy](http://www.salesforce.com/us/developer/docs/ajax/Content/sforce_api_ajax_queryresultiterator.htm#ajax_proxy) to give full access to the REST API. Since the AJAX proxy is present on all
14+
Visualforce hosts with an endpoint of the form https://abc.na1.visual.force.com/services/proxy, our Visualforce-hosted JavaScript can invoke it, passing the desired resource URL in an HTTP header. A drawback here is that using the REST API, even from a Visualforce page, consumes API calls.
15+
16+
To host JavaScript outside the Force.com platform, we can deploy a simple PHP proxy to perform the same function as the AJAX proxy.
1517

1618
[PhoneGap](http://www.phonegap.com/) provides a way for HTML5/JavaScript apps to run as native applications; in this configuration a proxy is not required - the toolkit simply provides a convenient abstraction of the REST API.
1719

@@ -23,10 +25,39 @@ The toolkit uses [jQuery](http://jquery.com/). It has been tested on jQuery 1.4.
2325
Configuration
2426
-------------
2527

26-
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*.
28+
RemoteTK requires no configuration.
29+
30+
ForceTK requires that you 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*.
31+
32+
Using RemoteTK in a Visualforce page
33+
------------------------------------
34+
35+
Add RemoteTKController.cls and RemoteTK.component to your org by creating an Apex Class and a Component and pasting in the respective content, pasting the files into a [Force.com IDE](http://wiki.developerforce.com/page/Force.com_IDE) project, or by using the [Force.com Migration Tool](http://wiki.developerforce.com/page/Migration_Tool_Guide).
36+
37+
Your Visualforce page will need to include the component, then create a client object, passing a session ID to the constructor. An absolutely minimal sample is:
38+
39+
<apex:page>
40+
<!-- Include the RemoteTK component -->
41+
<c:RemoteTK />
42+
<apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" />
43+
<script type="text/javascript">
44+
// Get a reference to jQuery that we can work with
45+
$j = jQuery.noConflict();
46+
47+
// Get an instance of the RemoteTK client
48+
var client = new remotetk.Client();
49+
50+
client.query("SELECT Name FROM Account LIMIT 1", function(response){
51+
$j('#accountname').html(response.records[0].Name);
52+
});
53+
</script>
54+
<p>The first account I see is <span id="accountname"></span>.</p>
55+
</apex:page>
56+
57+
A more fully featured sample is provided in [RemoteTKExample.page](Force.com-JavaScript-REST-Toolkit/blob/master/RemoteTKExample.page).
2758

28-
Using the Toolkit in a Visualforce page
29-
---------------------------------------
59+
Using ForceTK in a Visualforce page
60+
-----------------------------------
3061

3162
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*.
3263

RemoteTK.component

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
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+
<apex:component controller="RemoteTKController">
27+
<script>
28+
var remotetk = window.remotetk;
29+
30+
if (remotetk === undefined) {
31+
remotetk = {};
32+
}
33+
34+
if (remotetk.Client === undefined) {
35+
function unescapeHTML(input) {
36+
var y = document.createElement('textarea');
37+
y.innerHTML = input;
38+
return y.value;
39+
}
40+
41+
function handleResult(result, callback, error, nullok) {
42+
if (result) {
43+
result = JSON.parse(unescapeHTML(result));
44+
if ( Array.isArray(result) && result[0].message && result[0].errorCode ) {
45+
if ( typeof error === 'function' ) {
46+
error(result);
47+
}
48+
} else {
49+
callback(result);
50+
}
51+
} else if (typeof nullok !== 'undefined' && nullok) {
52+
callback();
53+
} else {
54+
error([{ message : "Null return from action method","errorCode":"NULL_RETURN"}]);
55+
}
56+
}
57+
58+
/**
59+
* The Client provides a convenient abstraction similar to the Force.com
60+
* REST API, allowing JavaScript in Visualforce pages access to data
61+
* without consuming API calls.
62+
* @constructor
63+
*/
64+
remotetk.Client = function(){
65+
}
66+
67+
/*
68+
* Completely describes the individual metadata at all levels for the
69+
* specified object.
70+
* @param objtype object type; e.g. "Account"
71+
* @param callback function to which response will be passed
72+
* @param [error=null] function to which jqXHR will be passed in case of error
73+
*/
74+
remotetk.Client.prototype.describe = function(objtype, callback, error) {
75+
RemoteTKController.describe(objtype, function(result){
76+
handleResult(result, callback, error);
77+
});
78+
}
79+
80+
/*
81+
* Creates a new record of the given type.
82+
* @param objtype object type; e.g. "Account"
83+
* @param fields an object containing initial field names and values for
84+
* the record, e.g. {:Name "salesforce.com", :TickerSymbol
85+
* "CRM"}
86+
* @param callback function to which response will be passed
87+
* @param [error=null] function to which jqXHR will be passed in case of error
88+
*/
89+
remotetk.Client.prototype.create = function(objtype, fields, callback, error) {
90+
RemoteTKController.create(objtype, JSON.stringify(fields), function(result){
91+
handleResult(result, callback, error);
92+
});
93+
}
94+
95+
/*
96+
* Retrieves field values for a record of the given type.
97+
* @param objtype object type; e.g. "Account"
98+
* @param id the record's object ID
99+
* @param [fields=null] optional comma-separated list of fields for which
100+
* to return values; e.g. Name,Industry,TickerSymbol
101+
* @param callback function to which response will be passed
102+
* @param [error=null] function to which jqXHR will be passed in case of error
103+
*/
104+
remotetk.Client.prototype.retrieve = function(objtype, id, fieldlist, callback, error) {
105+
RemoteTKController.retrieve(objtype, id, fieldlist, function(result){
106+
handleResult(result, callback, error);
107+
});
108+
}
109+
110+
/* NOT YET IMPLEMENTED!!!
111+
* Upsert - creates or updates record of the given type, based on the
112+
* given external Id.
113+
* @param objtype object type; e.g. "Account"
114+
* @param externalIdField external ID field name; e.g. "accountMaster__c"
115+
* @param externalId the record's external ID value
116+
* @param fields an object containing field names and values for
117+
* the record, e.g. {:Name "salesforce.com", :TickerSymbol
118+
* "CRM"}
119+
* @param callback function to which response will be passed
120+
* @param [error=null] function to which jqXHR will be passed in case of error
121+
*/
122+
/*
123+
remotetk.Client.prototype.upsert = function(objtype, externalIdField, externalId, fields, callback, error) {
124+
RemoteTKController.upser(objtype, externalIdField, externalId, JSON.stringify(fields), function(result){
125+
handleResult(result, callback, error, true);
126+
});
127+
}
128+
*/
129+
130+
/*
131+
* Updates field values on a record of the given type.
132+
* @param objtype object type; e.g. "Account"
133+
* @param id the record's object ID
134+
* @param fields an object containing initial field names and values for
135+
* the record, e.g. {:Name "salesforce.com", :TickerSymbol
136+
* "CRM"}
137+
* @param callback function to which response will be passed
138+
* @param [error=null] function to which jqXHR will be passed in case of error
139+
*/
140+
remotetk.Client.prototype.update = function(objtype, id, fields, callback, error) {
141+
RemoteTKController.updat(objtype, id, JSON.stringify(fields), function(result){
142+
handleResult(result, callback, error, true);
143+
});
144+
}
145+
146+
/*
147+
* Deletes a record of the given type. Unfortunately, 'delete' is a
148+
* reserved word in JavaScript.
149+
* @param objtype object type; e.g. "Account"
150+
* @param id the record's object ID
151+
* @param callback function to which response will be passed
152+
* @param [error=null] function to which jqXHR will be passed in case of error
153+
*/
154+
remotetk.Client.prototype.del = function(objtype, id, callback, error) {
155+
RemoteTKController.del(objtype, id, function(result){
156+
handleResult(result, callback, error, true);
157+
});
158+
}
159+
160+
/*
161+
* Executes the specified SOQL query.
162+
* @param soql a string containing the query to execute - e.g. "SELECT Id,
163+
* Name from Account ORDER BY Name LIMIT 20"
164+
* @param callback function to which response will be passed
165+
* @param [error=null] function to which jqXHR will be passed in case of error
166+
*/
167+
remotetk.Client.prototype.query = function(soql, callback, error) {
168+
RemoteTKController.query(soql, function(result){
169+
handleResult(result, callback, error);
170+
});
171+
}
172+
173+
/*
174+
* Executes the specified SOSL search.
175+
* @param sosl a string containing the search to execute - e.g. "FIND
176+
* {needle}"
177+
* @param callback function to which response will be passed
178+
* @param [error=null] function to which jqXHR will be passed in case of error
179+
*/
180+
remotetk.Client.prototype.search = function(sosl, callback, error) {
181+
RemoteTKController.search(sosl, function(result){
182+
handleResult(result, callback, error);
183+
});
184+
}
185+
}
186+
</script>
187+
</apex:component>

0 commit comments

Comments
 (0)