Showing posts with label MOSS 2007. Show all posts
Showing posts with label MOSS 2007. Show all posts

Friday, September 9, 2011

Direct link to a certain version of a document

In an order form I want to show a link to a document that contains the standard specifications of the goods. These specifications will change once in a while so it is important to know on what version of this document the order was based.
I can make use of a standard hyperlink field to add the shortcut to the document, that is the current version at that time. After the order is processed and archived to read-only, I want to be able to click the link to open the right version of the document, even though there are newer versions of it. The url of prior versions of a document is like: site/_vti_history/512/Documents/Specifications.pdf
The version is multiplied with the factor 512, so version 1.0 is 512, 2.0 is 1024, etc. With this knowledge I am able to reconstruct the url of the right version if I save the version number as well. But what if this version is still the current version? The reconstructed url doesn't work, because it should be: site/Documents/Specifications.pdf
Within a HTML <IMG> tag I can make use of the onError event to switch over to an alternative source, like I described in my part about adding icons to the refinement panel in SharePoint 2010. Unfortunately this trick will not work with href to a document. So I searched for an other way, and I found one: Checking if a file(url) exists using Javascript (AJAX). So all I have to do is turn the url into something like: href=javascript:check_file(url). The javascript code will then redirect me to the valid path of the document.

<script language="javascript" type="text/javascript">

http_check = getHTTPObject();

function getHTTPObject(){ 
  //Create a boolean variable to check for a valid Internet Explorer instance.
var xmlhttp = false;
//Check if we are using IE.
 try {
  //If the Javascript version is greater than 5.
  xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
 } catch (e) {
  //If not, then use the older active x object.
  try {
  //If we are using Internet Explorer.
  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
 } catch (E) {
//Else we must be using a non-IE browser.
xmlhttp = false;
 }
}
//If we are using a non-IE browser, create a javascript instance of the object.
 if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
 xmlhttp = new XMLHttpRequest();
 }
  return xmlhttp;
}

function check_file(path_of_file) 
{
    http_check.open("HEAD", path_of_file);
    http_check.onreadystatechange = handleHttpResponse_check;
    http_check.send(null);

    function handleHttpResponse_check()
    {
        if(http_check.readyState == 4){
            if (http_check.status == 200) {
                window.open(path_of_file);
            }else if (http_check.status == 404) {
                window.open(other_path_of_file);
            }
        }
    }
}
</script>
With the help of a workflow after submitting the form I want to modify the value of the hyperlink field to include the part: javascript:check_file(url). This doesn't seem to work in the browser.
So I am going to use a calculated column to compose the HTML code, to be rendered by the TextToHtml script from PathtoSharePoint.

Formula:
="<a href='javascript:' onclick="&CHAR(34)&"check_file('http://www.sharepointserver.eu/site/_vti_history/"&VALUE(LEFT(DocVersion;1))*512&"/Documents/Specifications.pdf')"&CHAR(34)&">Standard specifications</a>"

The javascript code with the redirect to the alternative -fixed- url of the current version:
function check_file(path_of_file) 
{
    http_check.open("HEAD", path_of_file);
    http_check.onreadystatechange = handleHttpResponse_check;
    http_check.send(null);

    function handleHttpResponse_check()
    {
        if(http_check.readyState == 4){
            if (http_check.status == 200) {
                window.open(path_of_file);
            }else if (http_check.status == 404) {
                window.open('http://www.sharepointserver.eu/site/Documents/Specifications.pdf');
            }else {
                window.open('http://www.sharepointserver.eu/site/Documents/Specifications.pdf');
            }
        }
    }
}
Somehow the "else if (http_check.status == 404)" doesn't work for the version url, so I use the "if anything else" to redirect to the url of the current version.

Now let's modify the user interface to put all the pieces together:
Add a CEWP to the NewForm.aspx (?toolpaneview=2) of the list and enter the link to the document, so the users can open the current version to read the specs.


Lookup the version number of the document by a workflow and add the value to a hidden (Allow management of content types, set Column Settings to Hidden) text field DocVersion, that is used in the formula of the calculated column.


Add a CEWP to the DispForm.aspx and/or the list view (display the calculated column) and paste the javascripts in the Source Editor. In this way the text in the calculated column is rendered as HTML and the javascript function check_file is executed on click of the link.
In this way there will be a redirect to the valid path of the right version.

Wednesday, August 24, 2011

What the hack?!? Not OOTB, but OTS

Adding metadata to uploaded documents automaticly, based on the context from where the Upload action was started.


From a dashboard (webpart page with related lists and library combined) I want to be able to start an upload action to add project documents to the library and want metadata (like project number, document type) added automaticly afterwards.
Well this is certainly not OOTB SharePoint. Normally you would set default values to columns before the upload, or use the Edit in Datasheet view to copy and paste properties to the documents after the upload.

We are going to combine several Off-The-Shelf scripts to get to the solution.
  1. TextToHTML-script from PathToSharePoint to render HTML-code from a calculated column so I can show an icon as upload "button" in the list view with a hyperlink that will call a javascript function with project data as variables.
  2. “sessvars.js” from Thomas Frank, also frequently used by Alexander from SharePoint JavaScripts, that let you use JavaScript session variables without using cookies. In this way I am able to store the context before the upload, and use it afterwards.
  3. SPServices, a jQuery Library for SharePoint Web Services, to use the function $().SPServices.SPUpdateMultipleListItems to update the document properties after the upload.
Download the scripts and add them to a Javascripts library in the site collection.


So I have a list for my projects and I will add a calculated column with HTML-code:
="<a href='javascript:upload(&#39;"&Projectnumber&"&#39;,&#39;Reports&#39;);'><img src='/_layouts/images/upload.gif' border='0' alt='Reports'></a>"

Then add a CEWP at the bottom of the dashboard page and paste the following script in the Source editor:

<script src="/Javascripts/sessvars.js" type="text/javascript"></script>
<script type="text/javascript">
sessvars.$.clearMem();
function upload(projectNumber,docType){
  sessvars.projectNumber = projectNumber;
  sessvars.docType = docType;
  sessvars.userId = _spUserId;
  var targetUrl = "/_layouts/Upload.aspx?List=%7BE69813A0%2D6E90%2D4D26%2D852A%2DBE0952C165CB%7D&RootFolder=%2FDocuments&Source=http%3A%2F%2Fwww%2Esharepointserver%2Eeu%2FPages%2FJavascript%2Easpx&MultipleUpload=1";
  window.location.href = targetUrl;
}
</script>

<script type="text/javascript">
/*
Text to HTML Lite - version 2.1.1
Questions and comments: Christophe@PathToSharePoint.com
*/
function TextToHTML(NodeSet, HTMLregexp) {
var CellContent = "";
var i=0;
while (i < NodeSet.length){
try {
CellContent = NodeSet[i].innerText || NodeSet[i].textContent;
if (HTMLregexp.test(CellContent)) {NodeSet[i].innerHTML = CellContent;}
} 
catch(err){}
i=i+1;
}
}
// Calendar views
var regexpA = new RegExp("\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*");
TextToHTML(document.getElementsByTagName("a"),regexpA);
// List views
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
</script>

The list view will show an upload button thanks to the TextToHTML script.
The javascript function will add the project number, document type and current user to the session variables, followed by a redirect to the standard upload page. You should replace the targetUrl with your own (click Upload Multiple Documents in the target library and copy the url). The source parameter refers to another page with javascript: /Pages/Javascript.aspx


Next step is to create this web part page, add a CEWP and paste the following script in the Source editor:

<script src="/Javascripts/sessvars.js" type="text/javascript"></script>
<script src="/Javascripts/jquery-1.6.2.min.js" type="text/javascript"></script>
<script src="/Javascripts/jquery.SPServices-0.6.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
var projectNumber = sessvars.projectNumber;
var docType = sessvars.docType;
var userId = sessvars.userId;
if((projectNumber!=undefined)&&(docType!=undefined)&&(userId!=undefined)){
  $().SPServices.SPUpdateMultipleListItems({ 
    listName: "Documents",
    CAMLRowLimit: 0,
    CAMLQuery: "<Query><Where><And><Eq><Fieldref Name='Author' LookupId='TRUE'/><Value Type='Integer'>" + userId + "</Value></Eq><IsNull><Fieldref Name='Projectnumber'/></IsNull></And></Where></Query>",
    valuepairs: [["Projectnumber", projectNumber], ["Documenttype", docType]]
  });
  sessvars.$.clearMem();
  window.location.href = "/Pages/Projects.aspx";
}
</script>

The session variables are read out and the values are used to update the documents that are selected by the CAML query: Created By the current user and no project number.
Finally the memory of the session variables is cleared and there's a redirect back to the dashboard page that will show the update document properties.


Thursday, August 18, 2011

At Poleposition

Ready, steady, GO!

At last my contribution to a better SharePoint for the world.

Improve to Approve.