function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
mikefmikef 

Hands-On: S-Controls and Buttons Session Help

Hi:

Thank you for attending one of my hands-on sessions on  S-Controls.
I hope Dreamforce was a great experience for you.

I have set up this discussion for class members to post and answer questions you might have after Dreamforce.

Please add your question under this post and a class participant or myself will answer you.

I will monitor this post for 2 weeks after Dreamforce.

Thank you

Here is the source:

Code:
<html>
<head>
<!-- Answers this is the working scontrol for class -->
<!-- author Michael Fullmore Salesforce.com -->
<!-- version .1 8/21/2007 -->
<!-- version 1.0 8/28/2007 -->

 <!-- addes the salesforce.com css file (look and feel) -->
 <link href="/dCSS/Theme2/default/common.css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet" type="text/css" />
 
 <!-- adding my own styles to this scontrol -->
 <style type="text/css">
  .edit{display:none;}
  p{width:70%}
 </style>
 
    <!-- these two script tags add the salesforce.com AJAX API and are required to "talk to salesforce" -->
    <script type="text/javascript" src="/js/functions.js"></script>
    <script src="/soap/ajax/10.0/connection.js"></script>
    
    <!-- this script tag starts our code, you can have as many script tags in your file as needed. we only need 1 for this demo -->
    <script type="text/javascript">
    
    //create the oppty object
    var opp = {id:"{!Opportunity.Id}", stage:"{!Opportunity.StageName}", nextStep:"{!Opportunity.NextStep}", description:"{!Opportunity.Description}"};
    
 //create an array of stages that we want to lock
    var lockedStages = ["Perception Analysis","Proposal/Price Quote","Negotiation/Review"," Closed Won","Closed Lost"];
    
    //checking to see if the user has access or not
    function doesUserHaveAccess(){
     //this is the first AJAX call, nice! Bonus points, what is it doing—
     var user = sforce.connection.getUserInfo();
     
     //get the profile name
     var profileNameQuery = sforce.connection.query("select Name from Profile where Id = '" + user.profileId + "'");
     var profileNameRecords = profileNameQuery.getArray("records");
     var profileName = profileNameRecords[0].Name;
     
     //next check if the user is locked out of oppty
     if(profileName == 'System Administrator'){ //adding TEST to the system administrator string to test with sys admin

      //using URLFOR to "skip over the override the second time around.
      window.parent.location.href = "{!URLFOR($Action.Opportunity.Edit, Opportunity.Id,[retURL=URLFOR($Action.Opportunity.View, Opportunity.Id)],true)}";
     }else{
           
      //if the user is not in the admin user group then we show the edit page for them. This page just gives us access to 3 fields on the opportunity
      showPage();
     }
    }
    
    function showPage(){
     document.getElementById('edit').style.display = 'block';
     document.getElementById('next').value = opp.nextStep;
     document.getElementById('des').value = opp.description;
    }
    
    //custom edit screen button actions
    function saveEdit(){
     //create an opportunity object
     var o = new sforce.SObject("Opportunity");
     
     //fill the opportunity SObject with data
      o.Id = opp.id;
      o.NextStep = document.getElementById('next').value;
      o.Description = document.getElementById('des').value;
      
     //save the SObject to salesforce, using the AJAX Tool Kit
     var saveO = sforce.connection.update([o]);
      if(saveO[0].getBoolean("success") == false){
       error(saveO[0]);
      }
     //go back to the opportunity
     window.parent.location.href = "/" + opp.id;
    }
    
    function cancelEdit(){
     window.parent.location.href = "/" + opp.id;
    }
    
    //help error function
    function error(e){
     alert("There is an error\n\n" + e);
    }
    
    //where the page starts it's loading
    function initPage(){
    
     var isLocked = false;
     //this function starts the process, every scontrol needs to start somewhere, and I like using initPage
     
     //first thing we need to do is check to see what stage the oppty is in.
     for(i=0; i<lockedStages.length; i++){
      if(opp.stage == lockedStages[i]){
       //if it's in a "locked" stage then we go and see if the user has access.
       isLocked = true;
       break;
      }
     }
     if(isLocked){
      doesUserHaveAccess();
     }else{
   //if the oppty is not is the "locked" stages then put up the normal edit page
      window.parent.location.href = "{!URLFOR($Action.Opportunity.Edit, Opportunity.Id,[retURL=URLFOR($Action.Opportunity.View, Opportunity.Id)],true)}";     
     }
    }
    
/****************************************************************************************************
**what's next–                      *
**Try adding a stage advancer, something that puts the opportunity in the next stage for the reps *
**Add your own fields                    *
**Display read only fields                   *
****************************************************************************************************/ 
    
    </script>
</head>
<body onload="initPage();" class="opportunity overviewPage">
 <div id="edit" class="edit">
  <div class=bPageTitle>
   <div class="ptBody secondaryPalette">
    <div class="content">
     <img class="pageTitleIcon" title="Opportunity" alt="Opportunity" src="/s.gif"/>
      <h1 class="pageType">Opportunity Edit (Custom)<span class="titleSeparatingColon">:</span></h1>
      <h2 class="pageDescription">{!Opportunity.Name}</h2>
      <br>
    </div>
   </div>
  </div>
  <div class="bPageBlock secondaryPalette">
   <div class="pbBody">
    <div class="pbSubsection">
     <p>This Opportunity is in a stage that is locked by your company. The only fields that you have access to are 
     Next Steps and Description. If you need to make edits to other fields please contact your Administrator. <br>Thank you.</p>
     <label for="next">Next Step:&nbsp;&nbsp;&nbsp;</label>
     <input type="text" id="next" size="80" />
     <br><br>
     <label for="des">Description:</label>
     <textarea id="des" cols="60" rows="5"></textarea>
     <br><br>
     <input type="button" id="btn1" value="Save" class="btn" onclick="saveEdit();" />
     <input type="button" id="btn2" value="Cancel" class="btn" onclick="cancelEdit();" />
    </div>
   </div>
  </div>
 </div>
</body>
</html>

 



Message Edited by mikef on 09-21-2007 11:59 AM

Atomic1Atomic1

Hi Mike,

Thanks for the great session on S-Controls.  Here's something I have had a request for from my users.  I'm hoping you can help me out.

On the opp field we capture user numbers which is the # of licenses we'll be selling on that opp.  MY sales team would like that number to auto-populate in the QTY field when you choose a product.  I was told this could be done with an S-Control.

Any help is appreciated.

Patrick PlawnerPatrick Plawner

Hi Mike and thanks for the good session today.

I need your advise. I am very new in all this and I was looking to create a button linked to an S-control, in order to update 2 fields, in some contacts, with always the same values.

I searched here, did some google search and could not find anything :(

Where such info could be found ? If you could provide a pointer or even the code, that would be so apreciated, as I need to start somewhere.

 

Many thanks,

Patrick.

Patrick PlawnerPatrick Plawner
And here is my first "buggy" code....
 
<html>
<head>
<title></title>

<script language="javascript" src="https://www.salesforce.com/services/lib/ajax/beta3.3/sforceclient.js" type="text/javascript"></script>

<script id="clientEventHandlersJS" language="javascript">

function initPage() {
sforceClient.registerInitCallback(setup);
sforceClient.setLoginUrl("https://www.salesforce.com/services/Soap/u/7.0");
sforceClient.init("{!API.Session_ID}", "{!API.Partner_Server_URL_70}", true);
}


function CloseReload() {
window.opener.location.reload();
window.close();
}

function setup() {
var mycontact = new Sforce.Dynabean("contact");

mycontact.set ("About_me__c", "SupplierRelations");

var saveResult = mycontact.save();

CloseReload();

}



</script>
</head>
<body onload="initPage()">
</body>
</html>

Message Edited by Patrick Plawner on 09-18-200709:41 PM

JasonSFJasonSF
Hi Mike,

Thanks for the class today.

I am a long time Java/PHP/Perl developer, new to salesforce, recently hired to solve some problems for a company with an Enterprise Edition salesforce installation.

One of these problems is with a custom s-control that uses url redirection with parent.frames.location.replace() to allow users to create a new custom object with a number of field values already populated from the object they were trying to "clone".

The problem arises when one of these fields has line returns in it, as this breaks the javascript URL building. They were building the URL with merge fields and lines like:

url += "&CF00N30000001J1iL="+"{!ESR__c.ESR_Quote_Notes__c}";

I solved this problem by instead doing a sforce.connection.query and passing the results to a javascript function that converts line returns to %0D so they are url safe (urlencoded).

I don't believe this is the most elegant solution to this problem, just the best one I could produce with my limited knowledge. I searched extensively for some kind of URLENCODE function that would do this for me but could not find any.

Since coming to dreamforce I have seen in the "force.com cookbook" and "creating on demand applications" a function called URLFOR. However I can not seem to find any documentation on URLFOR (input parameters, output, etc).

Will URLFOR correctly encode data it retrieves for URL redirection including special characters like newline?  If not what is the best way to populate a form creating a new object with values from an existing object that may include line returns. Also URLFOR seems to break whenever a custom field name to be passed in the URL starts with two leading 0's, as mentioned in this post

Thanks,
Jason



XmikeXmike

Jason,

When you get your SControl working, would you be so kind to post the entire Scontrol so us other newbies can see how you did it?

Thanks!

Mike

jason_hjason_h
Mike,
Thanks for a great session.  Would you be able to paste the sample S-control that we worked on in the class to this thread?  I'd like to use it as a starting point for a few ideas you inspired!

Thanks,
Jason Hunter

mikefmikef
Thank you for attending my session.

Here is the source for the answers. I will also post this on the main post for everyone.

Code:
<html>
<head>
<!-- Answers this is the working scontrol for class -->
<!-- author Michael Fullmore Salesforce.com -->
<!-- version .1 8/21/2007 -->
<!-- version 1.0 8/28/2007 -->

 <!-- addes the salesforce.com css file (look and feel) -->
 <link href="/dCSS/Theme2/default/common.css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet" type="text/css" />
 
 <!-- adding my own styles to this scontrol -->
 <style type="text/css">
  .edit{display:none;}
  p{width:70%}
 </style>
 
    <!-- these two script tags add the salesforce.com AJAX API and are required to "talk to salesforce" -->
    <script type="text/javascript" src="/js/functions.js"></script>
    <script src="/soap/ajax/10.0/connection.js"></script>
    
    <!-- this script tag starts our code, you can have as many script tags in your file as needed. we only need 1 for this demo -->
    <script type="text/javascript">
    
    //create the oppty object
    var opp = {id:"{!Opportunity.Id}", stage:"{!Opportunity.StageName}", nextStep:"{!Opportunity.NextStep}", description:"{!Opportunity.Description}"};
    
 //create an array of stages that we want to lock
    var lockedStages = ["Perception Analysis","Proposal/Price Quote","Negotiation/Review"," Closed Won","Closed Lost"];
    
    //checking to see if the user has access or not
    function doesUserHaveAccess(){
     //this is the first AJAX call, nice! Bonus points, what is it doing—
     var user = sforce.connection.getUserInfo();
     
     //get the profile name
     var profileNameQuery = sforce.connection.query("select Name from Profile where Id = '" + user.profileId + "'");
     var profileNameRecords = profileNameQuery.getArray("records");
     var profileName = profileNameRecords[0].Name;
     
     //next check if the user is locked out of oppty
     if(profileName == 'System Administrator'){ //adding TEST to the system administrator string to test with sys admin

      //using URLFOR to "skip over the override the second time around.
      window.parent.location.href = "{!URLFOR($Action.Opportunity.Edit, Opportunity.Id,[retURL=URLFOR($Action.Opportunity.View, Opportunity.Id)],true)}";
     }else{
           
      //if the user is not in the admin user group then we show the edit page for them. This page just gives us access to 3 fields on the opportunity
      showPage();
     }
    }
    
    function showPage(){
     document.getElementById('edit').style.display = 'block';
     document.getElementById('next').value = opp.nextStep;
     document.getElementById('des').value = opp.description;
    }
    
    //custom edit screen button actions
    function saveEdit(){
     //create an opportunity object
     var o = new sforce.SObject("Opportunity");
     
     //fill the opportunity SObject with data
      o.Id = opp.id;
      o.NextStep = document.getElementById('next').value;
      o.Description = document.getElementById('des').value;
      
     //save the SObject to salesforce, using the AJAX Tool Kit
     var saveO = sforce.connection.update([o]);
      if(saveO[0].getBoolean("success") == false){
       error(saveO[0]);
      }
     //go back to the opportunity
     window.parent.location.href = "/" + opp.id;
    }
    
    function cancelEdit(){
     window.parent.location.href = "/" + opp.id;
    }
    
    //help error function
    function error(e){
     alert("There is an error\n\n" + e);
    }
    
    //where the page starts it's loading
    function initPage(){
    
     var isLocked = false;
     //this function starts the process, every scontrol needs to start somewhere, and I like using initPage
     
     //first thing we need to do is check to see what stage the oppty is in.
     for(i=0; i<lockedStages.length; i++){
      if(opp.stage == lockedStages[i]){
       //if it's in a "locked" stage then we go and see if the user has access.
       isLocked = true;
       break;
      }
     }
     if(isLocked){
      doesUserHaveAccess();
     }else{
   //if the oppty is not is the "locked" stages then put up the normal edit page
      window.parent.location.href = "{!URLFOR($Action.Opportunity.Edit, Opportunity.Id,[retURL=URLFOR($Action.Opportunity.View, Opportunity.Id)],true)}";     
     }
    }
    
/****************************************************************************************************
**what's next–                      *
**Try adding a stage advancer, something that puts the opportunity in the next stage for the reps *
**Add your own fields                    *
**Display read only fields                   *
****************************************************************************************************/ 
    
    </script>
</head>
<body onload="initPage();" class="opportunity overviewPage">
 <div id="edit" class="edit">
  <div class=bPageTitle>
   <div class="ptBody secondaryPalette">
    <div class="content">
     <img class="pageTitleIcon" title="Opportunity" alt="Opportunity" src="/s.gif"/>
      <h1 class="pageType">Opportunity Edit (Custom)<span class="titleSeparatingColon">:</span></h1>
      <h2 class="pageDescription">{!Opportunity.Name}</h2>
      <br>
    </div>
   </div>
  </div>
  <div class="bPageBlock secondaryPalette">
   <div class="pbBody">
    <div class="pbSubsection">
     <p>This Opportunity is in a stage that is locked by your company. The only fields that you have access to are 
     Next Steps and Description. If you need to make edits to other fields please contact your Administrator. <br>Thank you.</p>
     <label for="next">Next Step:&nbsp;&nbsp;&nbsp;</label>
     <input type="text" id="next" size="80" />
     <br><br>
     <label for="des">Description:</label>
     <textarea id="des" cols="60" rows="5"></textarea>
     <br><br>
     <input type="button" id="btn1" value="Save" class="btn" onclick="saveEdit();" />
     <input type="button" id="btn2" value="Cancel" class="btn" onclick="cancelEdit();" />
    </div>
   </div>
  </div>
 </div>
</body>
</html>

 

mikefmikef

So to clarify S-Controls don't automate anything unless they are user invoked. With that said you can through unsupported ways invoke S-Controls but we can't talk about that here.

But you can have a button on the oppty that will calculate the quantity of the product line and populate it to the oppty.

The logic of the S-Control is simple; click on a button that takes quantity from product lines items and puts the value on the oppty in a field that is ready only on the page layout. If you make a field read only on the page layout it, forces the users to use the button to update this field.

Now you might want to look at the summation logic, this is the key.
1. Do all product quantities get summed?
2. Is there only a certain product that gets moved to the oppty?
3. What if?

So answering these questions will build the scope of the S-Control.

Hope this helps and let me know what else you need.

mikefmikef

Patrick:

Thanks for the post. Let's address both of your questions in one reply.

First: Where to start?
http://developer.salesforce.com is the best place to start.

Then once you get a good feel of what you can do in salesforce.com then check out the help and training link inside your account. They have great samples of code with real world issues.

Second: Your code example.

The main thing you need to change in your code is the AJAX took kit version; you are using the 3.3 beta version of the tool kit. Please change to the supported product version, my sample code has the correct version.

Also I would recommend downloading and installing Eclipse and the APEX plug-in for Eclipse, and creating your code that way. If you are using Eclipse then you are already there.

For you first S-Control take my example and follow the structure, I am not saying my code is the best, just that it will give you a place to start. You will adopt your own style as you get better with S-Controls, JavaScript, CSS, HTML, and the AJAX tool kit.

rockchick322004rockchick322004
Hi Patrick,

Are you trying to set values for custom fields?  If so, then you can use the Default Values functionality in Custom Fields to do that.  You can even check the User's Profile and other global information to determine the correct value if necessary.

Thanks,
Mary
Patrick PlawnerPatrick Plawner

Thanks Mike,

 

 

I tried but I am still struggleling.
If anyone could help me for this first piece of code, I think it would help me to start.

In the mean time, I will keep looking to all the places you pointed.


Many thanks already,
Patrick.

 

 

Patrick PlawnerPatrick Plawner

Hi Mary,

This is a custom field but I would like its value to change, only by clicking on a button. As not all records need to be affected by default.

Still searching....

Message Edited by Patrick Plawner on 09-23-2007 10:08 AM

mikefmikef

Jason:

Thanks for the post.

Your solution is the only way this can be done now. You have to pull the values out with the AJAX tool kit then construct your URL. If you want to use the create method in the AJAX tool kit you can, that way you don't have to pass anything through the URL.

There is documentation in the help of eclipse if you are using eclipse to create your S-Controls. All you do is create an SObject of type custom object, then fill up the values of fields, the save it. It's pretty straight forward.

The URLFOR method won't help you in this case, but all the documentation of this method is in the help and training link within salesforce.com. Just click on help and training then search for URLFOR.

Hope this helps and good luck

.
AngieAngie

Hi Mike,

Thank you for your presentation at the conference.  The S-control you created to prevent users from editing pages in certain opportunities stages will be helpful in the future. 

What I really wanted to see was how you create Detail Page Buttons.  I've used the temporary account to locate examples of buttons that had been created in the hope I could decipher what is wrong with my button but, I found that there aren't any examples of Detail Page Buttons.  Can you please point me to an example?  Or possibly provide an example of the on click Java script I should use? 

My button will be on the Products page.  I want the user to click that button to create a new opportunity with a specific record type.  It seems like this should be an easy thing to do but, my button isn't working.  Help!

Thanks in advance,

Angie

mikefmikef
Angie:

So when you say detail button there are really two ways to do this.

One is create a detail button in the custom button section of setup under the object you want the button on. This will put the button on the button header next to the New and other standard buttons.

Once you create the button you just need to "hook it up", and the help and training link is the best place to get an example of how to do that. Just search for buttons and you will get lots of examples on how to do this.

Now there is a little known, well everyone knows about it, but you can put a button on the page with a formula field. Basically you would create a text formula field and use the HYPERLINK(), and the IMAGE() formula to display the button you want. You can use this button app I created to build an SFDC button, button app.

Hope this helps, and good luck.
mikefmikef
OK thanks to everyone that submitted a post to this discussion, it is time to close this one down.

Please move all new questions to the correct discussion group, and contribute to the boards when you have time.

Thank you for attending my DF S-Controls session, and good luck.
AC1AC1

Hi Mike,

Here's something I have had a request for from my users.  I'm hoping you can help me out.

On the oppty products section we would like to pull in a value from a custom field within the products object when the product is added in an oppty. Can this be done with an S-Control?

Any help is appreciated.

Thanks, AC