Question

I'm using Sharepoint (WSS 3.0), which is unfortunately very limited in its ability to format survey questions (i.e., it strips any HTML you enter). I saw a solution elsewhere that suggested we add some JS to our master page file in order to allow line breaks. This works beautifully, but I'd like to see if we can allow links as well.

In our WSS surveys, I can now use {{br}} anywhere I want a line break (this works). I have tried extending the code to allow the use of link tags (e.g., {{link1}}url{{link2}}URL Title{{link3}}; but, this doesn't work, presumably because the updates aren't happening as a whole, and the browser then tries to render it piece by piece, confusing it. (FF and IE show different results, but both fail. If I mix up the order of the JS below -- i.e., do link3, 2 and then 1 -- the output changes as well, but still fails.) Is there a better way to do this?


<script language="JavaScript">
var className;
className = 'ms-formlabel';
var elements = new Array();
var elements = document.getElementsByTagName('td');
for (var e = 0; e < elements.length; e++)
{
if (elements[e].className == className){
elements[e].innerHTML = elements[e].innerHTML.replace(/{{br}}/g,'<br/>');
elements[e].innerHTML = elements[e].innerHTML.replace(/{{link1}}/g,'<a href="');
elements[e].innerHTML = elements[e].innerHTML.replace(/{{link2}}/g,'">');
elements[e].innerHTML = elements[e].innerHTML.replace(/{{link3}}/g,'</a>');}
}
</script>
Was it helpful?

Solution

Instead of modifying the innerHTML property in chunks (the browser tries to update the DOM each time you change innerHTML, which if you provide incomplete/broken markup, will obviously mess things up), do all your modifications against your own string variable, and then overwrite the entire innerHTML with your completed string:

<script language="JavaScript">
var className;
className = 'ms-formlabel';
var elements = new Array();
var elements = document.getElementsByTagName('td');
for (var e = 0; e < elements.length; e++)
{
if (elements[e].className == className) {
    var newHTML = elements[e].innerHTML;

    newHTML = newHTML.replace(/{{br}}/g,'<br/>');
    newHTML = newHTML.replace(/{{link1}}/g,'<a href="');
    newHTML = newHTML.replace(/{{link2}}/g,'">');
    newHTML = newHTML.replace(/{{link3}}/g,'</a>');}

    elements[e].innerHTML = newHTML;
}
</script>

OTHER TIPS

The simple answer would be to build up the innerHTML and replace it all at once:

for (var e = 0; e < elements.length; e++)
{
    if (elements[e].className == className) {
        var newHTML = elements[e].innerHTML;
        newHTML = newHTML.replace(/{{br}}/g,'<br/>');
        newHTML = newHTML.replace(/{{link1}}/g,'<a href="');
        newHTML = newHTML.replace(/{{link2}}/g,'">');
        newHTML = newHTML.replace(/{{link3}}/g,'</a>');
        elements[e].innerHTML = newHTML;
    }
}

The more complex answer would be to use capturing groups in your regex and pass a function as the 2nd parameter to replace(), so as to use a single call to replace() for the HTML. For example,

elements[e].innerHTML = elements[e].innerHTML.replace(/({{link1}})|({{link2}})|({{link3}})/g, 
    function (match) {
        var map = { 
            '{{link1}}' : '<a href="',
            '{{link2}}' : '>',
            '{{link3}}' : '</a>', }
        return map[match];
    });

The second solution is more complex and leads to some ugly regexes, but is more efficient than calling replace() over and over again.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top