
I build a lot of SharePoint Solutions that use JavaScript to enhance user experience. Most of the JavaScript I put in dedicated .js files and deploy them to the 12-hive (or 14-hive) in the layouts-folder. Deploying a JavaScript file (*.js) layouts-folder of SharePoint and loading external JavaScript files (*.js) in SharePoint 2007 can be accomplished in a couple of ways.
1) Add a Content Editor Web Part the the page and load the JavaScript using <script>-tags
Disadvantage: Need to add the Content Editor Web Part to every page necessary
2) Modify the Master Page and add <script>-tags to load the JavaScript
Disadvantage: Modifying the Master Page isn’t always allowed by customer
3) Add a Delegate Control to the AdditionalPageHead and reference the JavaScript from that control
Disadvantage: AdditionalPageHead is not available on all publishing pages
Furthermore, all methods described above will always load the JavaScript even if the file is not needed at the moment. Loading large JavaScript files increases page load times. However, it is possible to load a JavaScript from the layouts-folder (or a document library) on demand by using a Custom Action.
The following code will load a external JavaScript file by adding a reference to the head-section of the page:
var th = document.getElementsByTagName('head')[0]; var s = document.createElement('script'); s.setAttribute('id', jsidentifier); s.setAttribute('type','text/javascript'); s.setAttribute('src',jsname); th.appendChild(s);
It is possible to execute a function from that same JavaScript file as soon as the file is loaded. Because there are some differences between Internet Explorer, Firefox, Chrome and other browsers both the onreadystatechange and onload events are needed:
s.onreadystatechange = function () { if (s.readyState == 'complete') { MyExternalFunction(); } }; s.onload = function () { MyExternalFunction(); };
If you put both code snippets together and combine them with the SharePoint’s custom action tokens as described by Hristo Pavlov you get something like this:
var SiteUrl = '{SiteUrl}'; var ListId = '{ListId}'; var ItemId = '{ItemId}'; var jsidentifier = 'MyScript'; var jsname = '/_layouts/AlainDeKlerk.CustomAction/MyScript.js'; if (document.getElementById(jsidentifier) === null) { var th = document.getElementsByTagName('head')[0]; var s = document.createElement('script'); s.setAttribute('id', jsidentifier); s.setAttribute('type','text/javascript'); s.setAttribute('src',jsname); th.appendChild(s); s.onreadystatechange = function () { if (s.readyState == 'complete') { MyExternalFunction(SiteUrl, ListId, ItemId) } }; s.onload = function () { MyExternalFunction(SiteUrl, ListId, ItemId) }; } else { MyExternalFunction(SiteUrl, ListId, ItemId); }
The script above can be run from a Custom Action in SharePoint. That Custom Action will:
1) Only load the external JavaScript file when the action is clicked
2) Load the external JavaScript file only once
3) Execute a function from that external JavaScript file when the file is completely loaded
4) Pass the Custom Action tokens as parameters to a function in the external JavaScript file
Here is an example of a Custom Action adding a button to the ECB-menu using the script:
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <CustomAction Id ="AlainDeKlerk.CustomAction.MyScript" Title="Execute MyExternalFunction" Description="Loads a javascript on demand and executes a function from that file" Location="EditControlBlock" Rights = "AddListItems" Sequence="901" ImageUrl="/_layouts/images/TBSPRSHT.GIF" RegistrationType="ContentType" RegistrationId="0x0101"> <UrlAction Url="var SiteUrl = '{SiteUrl}'; var ListId = '{ListId}'; var ItemId = '{ItemId}'; var jsidentifier = 'MyScript'; var jsname = '/_layouts/AlainDeKlerk.CustomAction/MyScript.js'; if (document.getElementById(jsidentifier) === null) { var th = document.getElementsByTagName('head')[0]; var s = document.createElement('script'); s.setAttribute('id', jsidentifier); s.setAttribute('type','text/javascript'); s.setAttribute('src',jsname); th.appendChild(s); s.onreadystatechange = function () {if (s.readyState == 'complete') {MyExternalFunction(SiteUrl, ListId, ItemId) } }; s.onload = function () {MyExternalFunction(SiteUrl, ListId, ItemId) }; } else { MyExternalFunction(SiteUrl, ListId, ItemId); }" /> </CustomAction> </Elements>
If you are building a SharePoint 2010 solution you can use Script-On-Demand (SOD) library and load reference the script using the ScriptBlock or ScriptSrc tags in the CustomAction element.