My next step was to simplify it without using the WSDL and all that stuff. But this is not possible in Apex (please correct me, if I am wrong), so I had to look for an alternate way. My search ended up with AJAX Toolkit. And I learned AJAX for the first time then only. (Credit goes to Jeff, he made me learn two new technologies). I must tell you this is simply powerfullll. I used it in a visualforce page along with a small controller class (I had to use the class, its a different story). Later on I found that it is possible even without using the class. Here is how it looks like.
Input Screen |
And here is the generated visualforce code |
The logic is almost the same. You can even see variable names not very different. Below is the code for all this. (Please excuse me, code with no comments :)).
Page Code
<apex:page controller="OutputController">
<apex:form >
<script type="text/javascript">
var __sfdcSessionId = '{!GETSESSIONID()}';
</script>
<script src="../../soap/ajax/19.0/connection.js" type="text/javascript"></script>
<script type="text/javascript">
//var output='';
function setupPage() {
var obj = document.getElementById("obj");
var opt = document.getElementById("opt");
var rct = document.getElementById("rct");
var result;
try{
if(rct.value != '' && rct.value != null){
result = sforce.connection.describeLayout(obj.value, new Array(rct.value));
}else {
result = sforce.connection.describeLayout(obj.value);
alert(result);
alert('please note that you have not provided record type id. if the object has more than one record type and different page layout assignments, you will get the code with all the page layouts');
}
//call methods edit or details
if(opt.value == 'Edit')editLayoutResults(result, obj);
else detailLayoutResults(result, obj);
}catch(error){
var er = new String(error);
if(er.indexOf('INVALID_TYPE') != -1)alert('please check object api name');
document.getElementById("{!$Component.hide}").value = '';
}
}
//edit*****************************************layout
function editLayoutResults(result, obj) {
output = '';
var layouts = result.getArray("layouts");
output += '<' + 'apex' + ':' + 'page standardController=' + '"' + obj.value + '"' + '>';
output += '\n';
output += '<' + 'apex' + ':' + 'sectionHeader' + ' title=' + '"' + obj.value + ' Edit' + '"' + ' subtitle=' + '"' + '{' + '!' + obj.value + '.name}' + '"' + '/>';
output += '\n';
output += '<' + 'apex' + ':' + 'form' + '>';
output += '\n';
output += '<' + 'apex' + ':' + 'pageBlock title=' + '"' + obj.value + ' Edit' + '"' + ' mode=' + '"edit">';
output += '\n';
output += '\n';
output += '<' + 'apex' + ':' + 'pageBlockButtons location=' + '"top">';
output += '\n';
output += '<' + 'apex:commandButton value=' + '"' + 'Save' + '" ' + 'action=' + '"' + '{' + '!' + 'save' + '}"' + '/>';
output += '\n';
output += '<' + 'apex:commandButton value=' + '"' + 'Save & New' + '"' + ' action=' + '"' + '{' + '!save}" />';
output += '\n';
output += '<' + 'apex:commandButton value="Cancel" action=' + '"' + '{' + '!cancel}' + '"/>';
output += '\n';
output += '<' + '/apex:pageBlockButtons>';
output += '\n';
output += '\n';
output += '<' + 'apex' + ':' + 'pageBlockButtons location=' + '"bottom">';
output += '\n';
output += '<' + 'apex:commandButton value=' + '"' + 'Save' + '" ' + 'action=' + '"' + '{' + '!' + 'save' + '}"' + '/>';
output += '\n';
output += '<' + 'apex:commandButton value=' + '"' + 'Save & New' + '"' + ' action=' + '"' + '{' + '!save}" />';
output += '\n';
output += '<' + 'apex:commandButton value="Cancel" action=' + '"' + '{' + '!cancel}' + '"/>';
output += '\n';
output += '<' + '/apex:pageBlockButtons>';
//adding fields and sections
var allTheLayouts = result.getArray("layouts");
for (var i = 0; i < allTheLayouts.length; i++){
var layout = allTheLayouts[i];
if (layout.editLayoutSections != null){
var elSections = layout.getArray("editLayoutSections");
for (var j = 0; j < elSections.length; j++){
var els = elSections[j];
output += '\n';
output += '\n';
output += '<' + 'apex:pageBlockSection title=' + '"' + els.heading + '" ' + 'columns=' + '"' + els.columns + '"' + '>';
output += '\n';
var allTheLayoutRows = els.getArray("layoutRows");
for (var k = 0; k < allTheLayoutRows.length; k++){
var lr = allTheLayoutRows[k];
var lis = lr.getArray("layoutItems");
for (var h = 0; h < lis.length; h++){
var li = lis[h];
//only in case of Lead and Contact First Name, which includes Salutation also
if (li.layoutComponents != null && li.layoutComponents.length == 2){
output += '<' + 'apex:inputField value=' + '"' + '{' + '!' + obj.value + '.' + li.layoutComponents[1].value + '}' + '" ' + 'required=' + '"' + li.required.toString() + '"' + '/>';
output += '\n';
}
//for all other fields
else if (li.layoutComponents != null){
output += '<' + 'apex:inputField value=' + '"' + '{' + '!' + obj.value + '.' + li.layoutComponents.value + '}' + '" ' + 'required=' + '"' + li.required.toString() + '"' + '/>';
output += '\n';
}
}
}
output += '<' + '/apex:pageBlockSection>';
output += '\n';
}
}
}
output += '\n';
output += '<' + '/apex:pageBlock>';
output += '\n';
output += '<' + '/apex:form>';
output += '\n';
output += '<' + '/apex:page>';
document.getElementById("{!$Component.hide}").value = output;
}
//details**********************************layout
function detailLayoutResults(result, obj) {
var layouts = result.getArray("layouts");
var output = '';
output += '<' + 'apex' + ':' + 'page standardController=' + '"' + obj.value + '"' + '>';
output += '\n';
output += '<' + 'apex' + ':' + 'sectionHeader' + ' title=' + '"' + obj.value + '"' + ' subtitle=' + '"' + '{' + '!' + obj.value + '.name}' + '"' + '/>';
output += '\n';
output += '<' + 'apex' + ':' + 'pageBlock title=' + '"' + obj.value + '"' + '>';
output += '\n';
//adding fields and sections
var allTheLayouts = result.getArray("layouts");
for (var i = 0; i < allTheLayouts.length; i++){
var layout = allTheLayouts[i];
if (layout.editLayoutSections != null){
var elSections = layout.getArray("editLayoutSections");
for (var j = 0; j < elSections.length; j++){
var els = elSections[j];
output += '\n';
output += '<' + 'apex:pageBlockSection title=' + '"' + els.heading + '" ' + 'columns=' + '"' + els.columns + '"' + '>';
output += '\n';
var allTheLayoutRows = els.getArray("layoutRows");
for (var k = 0; k < allTheLayoutRows.length; k++){
var lr = allTheLayoutRows[k];
var lis = lr.getArray("layoutItems");
for (var h = 0; h < lis.length; h++){
var li = lis[h];
//only in case of Lead and Contact First Name, which includes Salutation also
if (li.layoutComponents != null && li.layoutComponents.length == 2){
output += '<' + 'apex:outputField title=' + '"' + li.label + '" value="' + '{' + '!' + obj.value + '.' + li.layoutComponents[1].value + '}' + '"' + '/>';
output += '\n';
}
//for all other fields
else if (li.layoutComponents != null){
output += '<' + 'apex:outputField title=' + '"' + li.label + '" value="' + '{' + '!' + obj.value + '.' + li.layoutComponents.value + '}' + '"' + '/>';
output += '\n';
}
}
}
output += '<' + '/apex:pageBlockSection>';
output += '\n';
}
}
}
output += '\n';
output += '<' + '/apex:pageBlock>';
output += '\n';
output += '<' + '/apex:page>';
document.getElementById("{!$Component.hide}").value = output;
}
</script>
<p><b>Enter the object API Name and record type Id associated to create visualforce code of the page layout for the selected page type.</b></p>
<table>
<tr >
<td><b>Object API Name</b></td>
<td><input type="text" id="obj"/></td>
</tr>
<tr >
<td><b>Record Type Id</b></td>
<td><input type="text" id="rct"/></td>
</tr>
<tr >
<td><b>Page Type</b></td>
<td><select id="opt">
<option value="Edit">Edit</option>
<option value="Detail">Detail</option>
</select></td>
</tr>
</table>
<center><apex:commandButton id="but" value="Create Page Code" onclick="setupPage()" action="{!create}" rerender="pan" status="pageStatus"/></center>
<apex:inputHidden id="hide" value="{!hide}"/>
<br><br></br></br>
<apex:actionStatus id="pageStatus" startText="Getting page code..." stopText="Page Code"/>
<table >
<tr>
<td>
<apex:outputPanel id="pan">
{!output}
</apex:outputPanel>
</td>
</tr>
</table>
</apex:form>
</apex:page>
<apex:form >
<script type="text/javascript">
var __sfdcSessionId = '{!GETSESSIONID()}';
</script>
<script src="../../soap/ajax/19.0/connection.js" type="text/javascript"></script>
<script type="text/javascript">
//var output='';
function setupPage() {
var obj = document.getElementById("obj");
var opt = document.getElementById("opt");
var rct = document.getElementById("rct");
var result;
try{
if(rct.value != '' && rct.value != null){
result = sforce.connection.describeLayout(obj.value, new Array(rct.value));
}else {
result = sforce.connection.describeLayout(obj.value);
alert(result);
alert('please note that you have not provided record type id. if the object has more than one record type and different page layout assignments, you will get the code with all the page layouts');
}
//call methods edit or details
if(opt.value == 'Edit')editLayoutResults(result, obj);
else detailLayoutResults(result, obj);
}catch(error){
var er = new String(error);
if(er.indexOf('INVALID_TYPE') != -1)alert('please check object api name');
document.getElementById("{!$Component.hide}").value = '';
}
}
//edit*****************************************layout
function editLayoutResults(result, obj) {
output = '';
var layouts = result.getArray("layouts");
output += '<' + 'apex' + ':' + 'page standardController=' + '"' + obj.value + '"' + '>';
output += '\n';
output += '<' + 'apex' + ':' + 'sectionHeader' + ' title=' + '"' + obj.value + ' Edit' + '"' + ' subtitle=' + '"' + '{' + '!' + obj.value + '.name}' + '"' + '/>';
output += '\n';
output += '<' + 'apex' + ':' + 'form' + '>';
output += '\n';
output += '<' + 'apex' + ':' + 'pageBlock title=' + '"' + obj.value + ' Edit' + '"' + ' mode=' + '"edit">';
output += '\n';
output += '\n';
output += '<' + 'apex' + ':' + 'pageBlockButtons location=' + '"top">';
output += '\n';
output += '<' + 'apex:commandButton value=' + '"' + 'Save' + '" ' + 'action=' + '"' + '{' + '!' + 'save' + '}"' + '/>';
output += '\n';
output += '<' + 'apex:commandButton value=' + '"' + 'Save & New' + '"' + ' action=' + '"' + '{' + '!save}" />';
output += '\n';
output += '<' + 'apex:commandButton value="Cancel" action=' + '"' + '{' + '!cancel}' + '"/>';
output += '\n';
output += '<' + '/apex:pageBlockButtons>';
output += '\n';
output += '\n';
output += '<' + 'apex' + ':' + 'pageBlockButtons location=' + '"bottom">';
output += '\n';
output += '<' + 'apex:commandButton value=' + '"' + 'Save' + '" ' + 'action=' + '"' + '{' + '!' + 'save' + '}"' + '/>';
output += '\n';
output += '<' + 'apex:commandButton value=' + '"' + 'Save & New' + '"' + ' action=' + '"' + '{' + '!save}" />';
output += '\n';
output += '<' + 'apex:commandButton value="Cancel" action=' + '"' + '{' + '!cancel}' + '"/>';
output += '\n';
output += '<' + '/apex:pageBlockButtons>';
//adding fields and sections
var allTheLayouts = result.getArray("layouts");
for (var i = 0; i < allTheLayouts.length; i++){
var layout = allTheLayouts[i];
if (layout.editLayoutSections != null){
var elSections = layout.getArray("editLayoutSections");
for (var j = 0; j < elSections.length; j++){
var els = elSections[j];
output += '\n';
output += '\n';
output += '<' + 'apex:pageBlockSection title=' + '"' + els.heading + '" ' + 'columns=' + '"' + els.columns + '"' + '>';
output += '\n';
var allTheLayoutRows = els.getArray("layoutRows");
for (var k = 0; k < allTheLayoutRows.length; k++){
var lr = allTheLayoutRows[k];
var lis = lr.getArray("layoutItems");
for (var h = 0; h < lis.length; h++){
var li = lis[h];
//only in case of Lead and Contact First Name, which includes Salutation also
if (li.layoutComponents != null && li.layoutComponents.length == 2){
output += '<' + 'apex:inputField value=' + '"' + '{' + '!' + obj.value + '.' + li.layoutComponents[1].value + '}' + '" ' + 'required=' + '"' + li.required.toString() + '"' + '/>';
output += '\n';
}
//for all other fields
else if (li.layoutComponents != null){
output += '<' + 'apex:inputField value=' + '"' + '{' + '!' + obj.value + '.' + li.layoutComponents.value + '}' + '" ' + 'required=' + '"' + li.required.toString() + '"' + '/>';
output += '\n';
}
}
}
output += '<' + '/apex:pageBlockSection>';
output += '\n';
}
}
}
output += '\n';
output += '<' + '/apex:pageBlock>';
output += '\n';
output += '<' + '/apex:form>';
output += '\n';
output += '<' + '/apex:page>';
document.getElementById("{!$Component.hide}").value = output;
}
//details**********************************layout
function detailLayoutResults(result, obj) {
var layouts = result.getArray("layouts");
var output = '';
output += '<' + 'apex' + ':' + 'page standardController=' + '"' + obj.value + '"' + '>';
output += '\n';
output += '<' + 'apex' + ':' + 'sectionHeader' + ' title=' + '"' + obj.value + '"' + ' subtitle=' + '"' + '{' + '!' + obj.value + '.name}' + '"' + '/>';
output += '\n';
output += '<' + 'apex' + ':' + 'pageBlock title=' + '"' + obj.value + '"' + '>';
output += '\n';
//adding fields and sections
var allTheLayouts = result.getArray("layouts");
for (var i = 0; i < allTheLayouts.length; i++){
var layout = allTheLayouts[i];
if (layout.editLayoutSections != null){
var elSections = layout.getArray("editLayoutSections");
for (var j = 0; j < elSections.length; j++){
var els = elSections[j];
output += '\n';
output += '<' + 'apex:pageBlockSection title=' + '"' + els.heading + '" ' + 'columns=' + '"' + els.columns + '"' + '>';
output += '\n';
var allTheLayoutRows = els.getArray("layoutRows");
for (var k = 0; k < allTheLayoutRows.length; k++){
var lr = allTheLayoutRows[k];
var lis = lr.getArray("layoutItems");
for (var h = 0; h < lis.length; h++){
var li = lis[h];
//only in case of Lead and Contact First Name, which includes Salutation also
if (li.layoutComponents != null && li.layoutComponents.length == 2){
output += '<' + 'apex:outputField title=' + '"' + li.label + '" value="' + '{' + '!' + obj.value + '.' + li.layoutComponents[1].value + '}' + '"' + '/>';
output += '\n';
}
//for all other fields
else if (li.layoutComponents != null){
output += '<' + 'apex:outputField title=' + '"' + li.label + '" value="' + '{' + '!' + obj.value + '.' + li.layoutComponents.value + '}' + '"' + '/>';
output += '\n';
}
}
}
output += '<' + '/apex:pageBlockSection>';
output += '\n';
}
}
}
output += '\n';
output += '<' + '/apex:pageBlock>';
output += '\n';
output += '<' + '/apex:page>';
document.getElementById("{!$Component.hide}").value = output;
}
</script>
<p><b>Enter the object API Name and record type Id associated to create visualforce code of the page layout for the selected page type.</b></p>
<table>
<tr >
<td><b>Object API Name</b></td>
<td><input type="text" id="obj"/></td>
</tr>
<tr >
<td><b>Record Type Id</b></td>
<td><input type="text" id="rct"/></td>
</tr>
<tr >
<td><b>Page Type</b></td>
<td><select id="opt">
<option value="Edit">Edit</option>
<option value="Detail">Detail</option>
</select></td>
</tr>
</table>
<center><apex:commandButton id="but" value="Create Page Code" onclick="setupPage()" action="{!create}" rerender="pan" status="pageStatus"/></center>
<apex:inputHidden id="hide" value="{!hide}"/>
<br><br></br></br>
<apex:actionStatus id="pageStatus" startText="Getting page code..." stopText="Page Code"/>
<table >
<tr>
<td>
<apex:outputPanel id="pan">
{!output}
</apex:outputPanel>
</td>
</tr>
</table>
</apex:form>
</apex:page>
Controller Class
public class OutputController {
//variables and getter/setter
public String output {get;set;}
public String hide {get;set;}
//action method of the button
public PageReference create() {
output = hide;
return null;
}
//test method
public static testMethod void testPage(){
Test.setCurrentPage(Page.VisualforceCodeCreator);
Test.startTest();
OutputController oc = new OutputController();
oc.create();
Test.stopTest();
}
}
The controller, I had to use for a reason. We cannot just print some text with HTML encoding in it in a visualforce page. The option I came across later on is to use HTMLENCODE() function in the page and you'll get rid of the controller.
Happy Clouding.
And its not my dialog but I love it...Human Knowledge belongs to the world.
That is awesome!
ReplyDeleteQuite handy :)
ReplyDeleteExcellent...thanks
ReplyDeleteHi Kishore . It is working fine and great job.
ReplyDeleteMy question here is
The page here is making the soap api call right .
how is it possible to access the soap in visualforce page without wsdl file or client application
whats the use of the belo script .
script src="../../soap/ajax/19.0/connection.js" type="text/javascript"
Thanks for this efforts
ReplyDeletethis is working except internal comments is not being pulled in. I know it's not a normal field, but I would have expected it to show in the decscribelayout call.
ReplyDelete@Drew which field are you referring by "internal comments".
Delete@Mohammad Swaleh. There is an Internal Comments field on Cases. It's not a field on the object, but's available on the page page layout. When the case is saved, those comments are added to Case Comments. That field is available on the standard edit page. thanks
DeleteI tried to test this. Looks like "Internal Comments" (API Name "Comments") is not returned in describe layout call for Case object. There are certain limitations on this field (e.g, you can't include this as inputField component in a VF page etc.).
DeleteThis comment has been removed by the author.
ReplyDeleteOk thanks. That's what I'm finding out myself. It's just another one of those SF quirks.
ReplyDelete