First Looks at Visual Workflows

From what I have seen so far Visual Workflows are designed to be used by Administrators without coding knowledge or experience. It is similar to Workflows. Workflows enable workflow rules to be set up that identify record changes that trigger workflow actions whereas Visual Workflows allow flows to be created that are applications that are user-triggered instead of event-triggered.
Downsides
Errors:
Errors are handled with an error message that simply says:

“An unhandled fault has occurred in this flow. Please contact your system administrator for more information. “.

It will send an email to you with more specific information on the exact error. An example that I received:

Encountered unhandled fault when running process eFNOL/301c00000008pFw exception by user/organization: 00Dc0000003tkkJ/{4} Source organization: 00DE0000000f0YX (null) ; nested exception is: 
    common.exception.ApiQueryException: 
Unit__c.Id FROM Unit__c WHERE (Unit__c.PolicyNumber__c = 'Varnson
                               ^
ERROR at Row:1:Column:39
invalid ID field: Varnson Policy 1
(There was a problem executing your command.) > RETRIEVE

caused by element : FlowRecordLookup.Unit_Lookup

caused by: ; nested exception is: 
	common.exception.ApiQueryException: 
Unit__c.Id FROM Unit__c WHERE (Unit__c.PolicyNumber__c = 'Varnson
                               ^
ERROR at Row:1:Column:39
invalid ID field: Varnson Policy 1
(There was a problem executing your command.) > RETRIEVE

Salesforce Error ID: 1170913603-43025 (-1680723869)

These emails point out exactly where the error occurred making it easy to fix but unfortunately, if I were to go back and fix this error, run the flow again and get another of the error handling messages from a different process, I wouldn’t get another email regarding the new error. To help with errors, I put debugging screens in between steps that would be passing variables to track the steps one at a time to see where errors were occurring.
UI

The only way to adjust the user interface (using css for example) is to embed the flow into a Visualforce page. That is done by adding the tag somewhere between the elements. This adds another level of security concerns: any user that can access the Visualforce page can also run the embedded flow. Internal users also will need the “Run Flows” permission. All this really does is add an additional step to the page and an additional set of code to be maintained when the page can be set up as a flow by itself. This is what it looks like:

flow1

When this is what we wanted:
flow2

 

Documents

The only way to add a document upload process to a Visual Workflow is to create a custom Apex class that behaves as a controller for a Visualforce page that references it. This is the same as the UI situation in that it requires extra code to write and maintain when the page can do that work by itself.

Development
I spent way too much time debugging a strange error that I was getting when running the flow that I set up. For the life of me I could not figure out why the error was occurring and since it wasn’t my first error (see above error reporting) I wasn’t receiving an email that pointed out the problem. Then I finally figured it out when I brought up the Schema Builder which pointed out a curiosity in the Field Information on the object:

 

flow3

 

 

When accessing fields and their data from the Flow Designer, the API Name is what is used. I was trying to reference what I thought was a number when it was actually a reference to another object. Unlike an IDE like Eclipse, the Flow Designer doesn’t send up alerts for errors like this.

Upsides

Versions
You can have several different versions of a single flow (but only one version of each flow can be active at a time).
Flow Designer
The user interface is very easy to use. It has all the components and resources that can be dragged and dropped onto the canvas. It is easy to create and edit custom variables.

Uploading a Document using Visualforce and a Custom Controller

Create a Visualforce page that references a controller (documented below). Note the enctype attribute on the <apex:form> tag. This Visualforce page uses only the fields necessary for uploading a document but can be expanded to include field for other records or documents in the process.

<apex:page controller="FileUploadController">
  <apex:sectionHeader title="Visualforce Example" subtitle="File Upload Example"/>
 
  <apex:form enctype="multipart/form-data">
    <apex:pageMessages />
    <apex:pageBlock title="Upload a File">
 
      <apex:pageBlockButtons >
        <apex:commandButton action="{!upload}" value="Save"/>
      </apex:pageBlockButtons>
 
      <apex:pageBlockSection showHeader="false" columns="2" id="block1">
 
        <apex:pageBlockSectionItem >
          <apex:outputLabel value="File Name" for="fileName"/>
          <apex:inputText value="{!document.name}" id="fileName"/>
        </apex:pageBlockSectionItem>
 
        <apex:pageBlockSectionItem >
          <apex:outputLabel value="File" for="file"/>
          <apex:inputFile value="{!document.body}" filename="{!document.name}" id="file"/>
        </apex:pageBlockSectionItem>
 
        <apex:pageBlockSectionItem >
          <apex:outputLabel value="Description" for="description"/>
          <apex:inputTextarea value="{!document.description}" id="description"/>
        </apex:pageBlockSectionItem>
 
        <apex:pageBlockSectionItem >
          <apex:outputLabel value="Keywords" for="keywords"/>
          <apex:inputText value="{!document.keywords}" id="keywords"/>
        </apex:pageBlockSectionItem>
 
      </apex:pageBlockSection>
 
    </apex:pageBlock>
  </apex:form>
</apex:page>

Create an Apex class that behaves as the controller in the Visualforce page. The upload() method is key.

public with sharing class FileUploadController {
 
  public Document document {
    get {
      if (document == null)
        document = new Document();
      return document;
    }
    set;
  }
 
  public PageReference upload() {
 
    document.AuthorId = UserInfo.getUserId();
    document.FolderId = UserInfo.getUserId(); // put it in running user's folder
 
    try {
      insert document;
    } catch (DMLException e) {
      ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error uploading file'));
      return null;
    } finally {
      document.body = null; // clears the viewstate
      document = new Document();
    }
 
    ApexPages.addMessage(new ApexPages.message(ApexPages.severity.INFO,'File uploaded successfully'));
    return null;
  }
 
}

Visualforce takes care of all the hard work by updating the document from the file that’s uploaded. All your controller class needs to do is store it. If you would like to attach the document to a specific record you will need to use the Attachment object instead of the Document object.

Notes

Make sure you take a look at the finally block in the controller code above. The finally block always executes when the try block exits regardless if an error occurs or not. You need to ensure you clear out document’s body (document.body = null) so that the blob is not automatically included in the serialized image of the controller. If you do not clear out the body, you’ll get the following view state error: “Maximum view state size limit (128K) exceeded. Actual viewstate size for this page was…”

Store Multiple Values Together in a Flow

Store multiple values together—so that you can operate on them—by using the new collection variable flow resource. Collection variables can store both manually entered values and values from flow resources, such as email addresses entered in a flow’s screen. Using collection variables can help you conserve limits by not querying the Salesforce database for that information.

Previously, you couldn’t store manually entered values or values from another flow resource. Both sObject variables and sObject collection variables can store multiple values, but they must be field values.

Create a collection variable from the Resources tab in the Cloud Flow Designer by double-clicking Collection Variable.

Unlike with variables, sObject variables, and sObject collection variables, you can’t use Record Lookup or Fast Lookup elements to populate a collection variable. To populate a collection variable, add values whose data type matches the collection variable by using an Assignment. In other words, don’t try to add a variable of type Text to a collection variable of type Number.forcecom_process_collvar

God Mode in Windows 7 and Later

“God Mode” (aka Master Control Panel) Found in Windows 7 and Later

Just create a new folder anywhere in Windows. You can create it on Desktop or within Windows Explorer and give it following name:
God Mode.{ED7BA470-8E54-465E-825C-99712043E01C}
Now you’ll have access to all Control Panel settings page in a single place as shown in following screenshot:

Windows_7_Gode_Mode

Disable Charms Bar in Windows 8

1. Press “WIN+R” key combination to launch RUN dialog box then type regedit and press Enter. It’ll open Registry Editor and go to following key:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ImmersiveShell\

2. Under ImmersiveShell key, create a new key EdgeUI.

3. Now select newly created key “EdgeUI” and in right-side pane, create a new DWORDDisableCharmsHint and set its value to 1

Disable_Charms_Bar_Hint_Windows_8

4. That’s it. It’ll immediately disable Charms Bar hint feature. You’ll not need to log off or restart the system.

NOTE: If you want to enable the Charms Bar hint feature again, simply delete the DWORD “DisableCharmsHint” or set its value to 0

apex:page cache=”false”

Setting this to false will lead to increased bandwidth usage. Salesforce advises only setting to “false” during development or when truly necessary.  Also, there is another property “expires” which is closely related: Sites provide caching options that allow you to leverage the resources of our Content Delivery Network (CDN) partner to improve page load times and site performance, as well as help you avoid reaching bandwidth or service request time limits. Sites allows you to set the cache duration for each of your site pages and optimize content delivery to your end users.  A public Visualforce page on a Force.com Site may make a number of queries, or even call outs to external web sites. This will slow down the rendering of the page. You can ensure that page is rendered much snappier by configuring the page to be cached.
Control the caching behavior for your site by setting the Boolean cache attribute and integer expires attribute on each Visualforce page. By default, pages that do not have the cache attribute set are cached for ten minutes (600 seconds). Force.com uses a global content distribution network. For example, the first user to access the page in the UK will probably not hit the cache. Subsequent calls by that user, or any others in the UK, will hit the cache (provided that the page cache hasn’t expired). Use static resources to ensure other items your page references are also cached – like CSS and image files.
Be sure to use caution when caching pages that may display private information. For example let’s pretend you have a webform that creates a cookie and then autofills the form based on the cookie values when a user returns in the future. A page like this should not be cached. What will happen is if the page is not currently cached the associated Apex will run and autofill the form. This data will then reside in the form for the next 10 minutues or the length of the expires time. Anyone that visits the page while it is cached during this time will see the values that were populated by the Apex cookie values.

Hosted JQuery and Bootstrap Libraries

Decreased Latency

A CDN distributes your static content across servers in various, diverse physical locations. When a user’s browser resolves the URL for these files, their download will automatically target the closest available server in the network.

In the case of Google’s AJAX Libraries CDN, what this means is that any users not physically near your server will be able to download jQuery faster than if you force them to download it from your arbitrarily located server. There are a handful of CDN services comparable to Google’s, but it’s hard to beat the price of free! This benefit alone could decide the issue, but there’s even more.

Increased parallelism

To avoid needlessly overloading servers, browsers limit the number of connections that can be made simultaneously. Depending on which browser, this limit may be as low as two connections per hostname. Using the Google AJAX Libraries CDN eliminates one request to your site, allowing more of your local content to downloaded in parallel. It doesn’t make a gigantic difference for users with a six concurrent connection browser, but for those still running a browser that only allows two, the difference is noticeable.

Better caching

Potentially the greatest benefit of using the Google AJAX Libraries CDN is that your users may not need to download jQuery at all. No matter how well optimized your site is, if you’re hosting jQuery locally then your users must download it at least once. Each of your users probably already has dozens of identical copies of jQuery in their browser’s cache, but those copies of jQuery are ignored when they visit your site.

However, when a browser sees references to CDN-hosted copies of jQuery, it understands that all of those references do refer to the exact same file. With all of these CDN references point to exactly the same URLs, the browser can trust that those files truly are identical and won’t waste time re-requesting the file if it’s already cached. Thus, the browser is able to use a single copy that’s cached on-disk, regardless of which site the CDN references appear on.

This creates a potent “cross-site caching” effect which all sites using the CDN benefit from. Since Google’s CDN serves the file with headers that attempt to cache the file for up to one year, this effect truly has amazing potential. With many thousands of the most trafficked sites on the Internet already using the Google CDN to serve jQuery, it’s quite possible that many of your users will never make a single HTTP request for jQuery when they visit sites using the CDN. Even if someone visits hundreds of sites using the same Google hosted version of jQuery, they will only need download it once!

Links to JQuery Libraries: https://developers.google.com/speed/libraries/devguide#jquery

Links to Bootstrap Libraries:  http://www.bootstrapcdn.com/

 

Latest Bootstrap Media Queries Breakpoints

As of now these are the best breakpoints to use:

/*==================================================
=            Bootstrap 3 Media Queries             =
==================================================*/

/*==========  Mobile First Method  ==========*/

/* Custom, iPhone Retina */ 
@media only screen and (min-width : 320px) {
    
}

/* Extra Small Devices, Phones */ 
@media only screen and (min-width : 480px) {

}

/* Small Devices, Tablets */
@media only screen and (min-width : 768px) {

}

/* Medium Devices, Desktops */
@media only screen and (min-width : 992px) {

}

/* Large Devices, Wide Screens */
@media only screen and (min-width : 1200px) {

}


/*==========  Non-Mobile First Method  ==========*/

/* Large Devices, Wide Screens */
@media only screen and (max-width : 1200px) {

}

/* Medium Devices, Desktops */
@media only screen and (max-width : 992px) {

}

/* Small Devices, Tablets */
@media only screen and (max-width : 768px) {

}

/* Extra Small Devices, Phones */ 
@media only screen and (max-width : 480px) {

}

/* Custom, iPhone Retina */ 
@media only screen and (max-width : 320px) {
    
}

Using JavaScript to manipulate the page layout and state based on user interaction.

JavaScript directly on the page works fine but when you move it to its own external .js file as a static resource it bypasses the Visualforce rendering engine.   To override that behavior, wrapping the code in a document.ready handler.

This won’t render:

document.getElementById('glassNext1').addEventListener('click',function next(){
    		showCheck('checkmark');
			show_Check('check_mark');
			makeActive('step2'); 
			make_Active('step_2');
			toggleDiv('thumbs');
			show('progressDivGlass2');
	});

This will render:

$(function(){
    document.getElementById('glassNext1').addEventListener('click',function next(){
			showCheck('checkmark');
			show_Check('check_mark');
			makeActive('step2'); 
			make_Active('step_2');
			toggleDiv('thumbs');
			show('progressDivGlass2');
	});
});

Best practices for using font-weights

The CSS “font-weight” property is used to define the weight of a font, such as regular or bold. This article describes how to best use font families that have extended weights that may range from Extra Light all the way to Extra Black.

Here is how a regular and bold weight would be defined:

But for all other weights a numerical range from 100 to 900 is used. One of the challenges with web fonts is that most web browsers do not properly support font weights other than normal & bold. The following chart describes the possible mappings of weights to the numeric definitions:

  • 100    Extra Light or Ultra Light
  • 200    Light or Thin
  • 300    Book or Demi
  • 400    Normal or Regular
  • 500    Medium
  • 600    Semibold, Demibold
  • 700    Bold
  • 800    Black, Extra Bold or Heavy
  • 900    Extra Black, Fat, Poster or Ultra Black