| | Stumble It! | Add to Mixx! | | diigo it | | Slashdot |

Wednesday, March 31, 2010

Simple JQuery Form Sanitation

So I'm taking my first stab at publishing code based on JQuery. To make this code work, you need to have the JQuery script added to your page which is as easy as adding this block of code to the <HEAD> of your page:
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js'></script>
Once you've added this line to your page, you can add the following code:
<script type='text/javascript'>
$(document).ready(function(){ $(':input').blur(function() { $(this).val($(this).val().replace(/<[^>]*>/g,'')); }); });
</script>
Great, so what the heck does that do? This code will remove any HTML tags from user input on your site so if you want some HTML input, you'll have to modify my code. Otherwise this will go a long way towards preventing injection attacks on your site.

Friday, March 26, 2010

SharePoint - Prevent User from Selecting Certain Dates

I've been getting smart on jQuery a lot lately and haven't had a lot of time to spend on cool new SharePoint hacks, but yesterday I had a request to add this little feature to one of the lists that I manage.

Very generally speaking, the list coordinates network maintenance and we've found that submitters won't check to see if a day is full of maintenance events before they submit a request. My task was to add a function to the form to check if the day that had been selected was flagged as full.

My solution came in a few steps:
  1. Create a second list that just contains dates that have been flagged as full. The maintenance coordinators simply add new dates to this list as they fill up. You'll need to go through the code of this list and pull out the ID attribute for the table. Load the page in your browser, view the source code, and look for a table tag with the class of "ms-listviewtable". This is the ID that you want to copy. Also copy the URL for the list. You'll need to provide both strings to the script below.
  2. Add this JavaScript code to a Content Editor Web Part on the NewForm.aspx page (using the "NewForm.aspx?ToolPaneView=2" trick) to pull, parse, and compare the dates that have been flagged as full to the dates that have been selected in a date field.
    <script type='text/javascript'>

    var tbl_id = 'YOUR BIG LONG TABLE ID GOES HERE!!!';
    var url = 'http://path/to/your/List/AllItems.aspx';

    function read_locked_dates() {
    var ifm = document.getElementById('locked_days_list');
    if (ifm.src != url) { ifm.src = url; return false; }
    var doc = (ifm.contentWindow) ? ifm.contentWindow.document : ifm.contentDocument;
    var tbl = doc.getElementById(tbl_id);
    var nobrs = tbl.getElementsByTagName('nobr');
    for (var n=0;n<nobrs.length;n++) {
    blocked_dates.push(nobrs[n].innerHTML);
    }
    }

    function insert_date_check() {
    // this will detect manual updates to the date
    var inputs = document.getElementsByTagName('input');
    for (var i=0;i<inputs.length;i++) {
    if (inputs[i].parentNode.className == 'ms-dtinput') {
    if (inputs[i].attachEvent) { inputs[i].attachEvent('onchange',check_this_date); }
    else { inputs[i].addEventListener('change',check_this_date,false); }
    }
    }
    // this will detect updates to the dates done via the calendar clicker
    var ifms = document.getElementsByTagName('iframe');
    for (var i=0;i<ifms.length;i++) {
    if (ifms[i].getAttribute('title').match(/Select a date from the calendar./i)) {
    if (ifms[i].attachEvent) { ifms[i].attachEvent('onload',check_this_date); }
    else { ifms[i].addEventListener('click',check_this_date); }
    }
    }
    }

    function check_this_date() {
    var picked_dates = [];
    var dates = document.getElementsByTagName('input');
    for (var d=0;d<dates.length;d++) {
    if (dates[d].id.match(/DateTimeField/i)) {
    picked_dates.push(dates[d].value);
    for (var b=0;b<blocked_dates.length;b++) {
    if (dates[d].value == blocked_dates[b]) {
    dates[d].style.background = 'red';
    dates[d].value = 'date blocked';
    return false;
    } else {
    dates[d].style.background = '';
    }
    }
    }
    }
    }
    var out = document.getElementById('output');
    var blocked_dates = [];
    _spBodyOnLoadFunctionNames.push('read_locked_dates');
    _spBodyOnLoadFunctionNames.push('insert_date_check');

    </script>
Once you've added this to your NewForm.aspx page, anytime someone tries to edit a date field, it will check the date they've picked against the list you provide & prevent them from picking the date if it's flagged.

Cheers!

Tuesday, March 2, 2010

Simple AJAX Progress Bar

Below is some sample code that I'm posting to help point other developers in the right direction when attempting to create a progress bar for an AJAX function. This isn't 100% or even cross-browser compatible exactly, but I have tested it successfully on the current stable Chrome release.

Say you have a 'for' loop that runs an AJAX function for every item in an array and you want to view the progress of the function. Here's how I solved that problem:
<html>
<head>
<title>
</title>
<script type='text/javascript'>
function startAjax() {
// ... define yourArray[] for AJAX processing
for (var i=0;i<yourArray.length;i++) {
// loop through each item in the array and perform an AJAX process on it.
setTimeout('onReadyStateChangeFn("'+(Number(i)/Number(yourArray.length))*100+'%")',1000);
}
}

function onReadyStateChangeFn(perc) {
// ...
if (ajaxObj.readyState == 4 && ajax.status == 200) {
// ... your ajax-handling code here
document.getElementById('pbar_bar').style.width = perc;
// ... any additional code
}
}
</script>
</head>
<body>
<div id='pbar_frame' style='background:red;border:1px black solid;width=100%;height:1em;'>
<div id='pbar_bar' style='background:lime;width:0%;height:1em;'></div>
</div>
</body>
</html>
The key ingredient was 'setTimeout()', without it, the page would appear to hang while the 'for' loop executed.

Enjoy!