3

SharePoint 2010, at least, has an odd format for storing its lists' hyperlink fields on the backend, namely it uses

[URL], [Description]

"Well then what does it do about commas in the URL" you might ask.

"It encodes them, right? Because that would be sane and easy to manage."

Nope. Interestingly, SP duplicates every comma in the URL but not the description.

So the URL and description

"http://butts.com/a,b,c,d,,,lol" and "Butts.com,,, i,s awe,,some"

becomes

"http://butts.com/a,,b,,c,,d,,,,,,lol, Butts.com,,, i,s awe,,some"

A simple web service call to lists.asmx or listdata.svc to pull items from a list that has a hyperlink column will return you data for that field that has to be parsed, obviously, before you can use the URL in an href, redirect, or anything else.

Now, URL's are not supposed to have commas in them in the first place, but any browser is going to internally escape any commas, so in practice, especially in SP with typical document file names, you end up with commas to deal with, so you really do need a bullet-proof method for handling SP's particular method of formatting.

I have an imperative solution, I think, but is there a more elegant way to handle all cases?

4
  • I am posting a problem about the best way to handle SharePoint hyperlink string format using only JavaScript. I then propose my own solution to the problem.
    – AnalyticD
    Commented Jan 11, 2015 at 4:03
  • No, you are not asking a question, you answer it yourself already in the question body. That is not the format of this site Commented Jan 13, 2015 at 17:08
  • @RobertLindgren If my answer below was deleted, then the question of parsing the hyperlink format with pure JS would still remain. I don't see where that is solved above.
    – AnalyticD
    Commented Jan 14, 2015 at 21:20
  • The new formulations in your question body makes it a question, I'll reopen it Commented Jan 15, 2015 at 6:07

2 Answers 2

2

Now, 95% of cases are going to be solved by the trivial substring(0, indexof(', ')). But the edge cases are trickier.

function parseSPLink(SPlink)
{
    if(SPlink.indexOf(",,")==-1 || SPlink.indexOf(", ")<SPlink.indexOf(",,"))
    {
        return SPlink.split(",")[0];
    }

    //if there isn't a double comma in the string or the separator comes
    // before the first double comma, then we know that the first
    //comma must be the separator, so we just return the text before that 
    //Otherwise we loop until we find the right index

    else 
    {
        var ind = SPlink.indexOf(",,");
        var ind2 = ind;
        var temp = SPlink;

        while(temp.substring(ind+2).indexOf(",,")!=-1)
        {
            temp = temp.substring(ind+2);
            ind=temp.indexOf(",,");
            ind2 = ind2 + ind + 2;
        }

        ind2 = ind2 + 2 + temp.substring(ind+2).indexOf(", ");

        return SPlink.substring(0,ind2).replace(/,,/g,",");
    }
};

Now, this code works fine (as in, I haven't been able to break it anyway, but I haven't unit tested it.)

Then I started wondering how short a regex you could write. I immediately realized I needed negative lookbehind, which JS doesn't support AFAIK. So instead, we just reverse the string and use negative lookahead. Haha. So here we go:

function parseSPLinkRegex(SPLink)
{
    var rev = SPLink.split('').reverse().join('');
    return rev.substring(rev.search(/ ,(?!,)/g)+2)
        .split('').reverse().join('')
        .replace(/,,/g, ',');
}

I haven't tested this approach much. It might mangle unicode stuff due to the naive reverse, but I think the second reverse would resolve those, but IDK. EDIT: This code breaks for descriptions that contain ", " :(

Feel free to golf this. I just figured I would post it since this trivial problem broke all my links right before I had a demo so I looked like a jackass.

1
  • Obligatory: "When you use regex to solve a problem, now you have two problems."
    – AnalyticD
    Commented Jan 8, 2015 at 21:02
0

One way to avoid the problem would be to retrieve the URL data via the JavaScript client side object model instead of via the lists.asmx or listdata.svc web services.

ExecuteOrDelayUntilScriptLoaded(function(){
    var listName = "My List Name"; // List title
    var linkField = "Hyperlink_x0020_Field"; // Column internal name
    var clientContext = new SP.ClientContext();
    var list = clientContext.get_web().get_lists().getByTitle(listName);
    var caml = "<Query></Query>"; //pretend this is a good CAML query
    var camlQuery = new SP.CamlQuery();
    camlQuery.set_viewXml("<View>"+caml+"<RowLimit>1</RowLimit></View>");
    var items = list.getItems(camlQuery);
    clientContext.load(items);
    clientContext.executeQueryAsync(Function.createDelegate(this,function(){
        var enumerator = items.getEnumerator();
        while(enumerator.moveNext()){
            var item = enumerator.get_current();
            alert("Description: " + item.get_item(linkField).get_description());
            alert("URL: " + item.get_item(linkField).get_url());
        }
    }),Function.createDelegate(this,function(sender,args){alert(args.get_message())}));
},"SP.JS");

The obvious caveat with such an approach is that you are restricted by the JavaScript CSOM's limitations. For example the JSCSOM only lets you access content within the same site collection and does not provide for impersonation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.