Tuesday, July 22, 2014

SharePoint 2010 - JavaScript Client - Updating items with visual feedback to user

I had created a custom action for a document library in SharePoint 2010.
When the user presses the custom action button in the ribbon bar, the selected documents should be updated in a special field ("Document Status").
I noticed, that the procedure to update the selected documents takes long time. During the update process the user cannot see what is happening, because of the asynchronous update request via JavaScript.
I thought, this is not very user-friendly, so I created a screen, where the user can see what the system is doing in this moment.
Here is my code with some screenshots.

function ApproveDocuments() {
    var ApprovalProcess = this;
    ApprovalProcess.SiteCollectionUrl = '';
    var counter = 0;
    var fileItems = [], item, docsSentToApproval = [];

    var ClientContext = SP.ClientContext.get_current();
    var LibraryID = SP.ListOperation.Selection.getSelectedList();
    var Library = ClientContext.get_web().get_lists().getById(LibraryID); //Gets the current Library
    var SelectedDocuments = SP.ListOperation.Selection.getSelectedItems(ClientContext);
    var SiteCollection = ClientContext.get_site();
    ClientContext.load(SiteCollection);
    ClientContext.executeQueryAsync(function (s, a) {
        jQuery('#myCloseInfoDivButton').click(function () {
            window.location.href = SiteCollection.get_url() + '/Lists/Document Center';
            ApprovalProcess.SiteCollectionUrl = SiteCollection.get_url();
        });
    });

    var newDiv = '<div id="myCoverAll" style="background-color:#182738;width:100%;height:100%;position:fixed;top:0px;left:0px;display:block;z-index:1000;filter:alpha(opacity=70);-ms-filter:alpha(opacity=70);opacity:0.7;"></div>';
    newDiv += '<DIV id="myInfoDivContainer" class="ms-dlgBorder" style="background-color:#ffffff;HEIGHT: 345px; WIDTH: 609px; position:absolute; left:50%; margin-left:-304px; top:50%; margin-top:-172px;z-index:1001;">';
    newDiv += ' <DIV class="ms-dlgTitle" style="CURSOR: default; WIDTH: 609px">';
    newDiv += ' <SPAN class="ms-dlgTitleText" id="dialogTitleSpan" style="WIDTH: 545px">Approve Documents</SPAN>';
    newDiv += '</DIV>';
    newDiv += '<DIV id="myInfoDivData" class="ms-dlgFrameContainer" style="background-color:#ffffff;padding-top:20px;"></DIV>';
    newDiv += '<div id="myButtonCloseDiv" style="position:relative;width:100px;left:50%;margin-left:-50px;background-color:#ffffff;padding-top:20px;"><input class="ms-toolbar" type="button" name="myCloseInfoDivButton" id="myCloseInfoDivButton" value=" Close " /></DIV>';
    newDiv += '</DIV>';
    jQuery("#aspnetForm").after(newDiv);
    if (SelectedDocuments.length > 0) {
        jQuery('#myCloseInfoDivButton').attr('disabled', 'disabled');
    }

    for (var currentItem in SelectedDocuments) {
        item = Library.getItemById(SelectedDocuments[currentItem].id);
        fileItems.push(item);
        ClientContext.load(item, 'FileLeafRef','Id','DocumentStatus');
    }

    var newElementHtmlHeader;
    newElementHtmlHeader = '<div style="position:relative;width:100px;left:50%;margin-left:-50px;display:block;vertical-align:middle; text-align:center;" id="myLoadingBar"><img src="' + ApprovalProcess.SiteCollectionUrl + '_layouts/images/mySPProject/busy.gif" /><br />Loading...</div>';
    newElementHtmlHeader += '<div style="font-weight:bold;float:left;padding:3px;width:50px;display:table-cell; vertical-align:middle; text-align:center;">Approval Status</div>';
    newElementHtmlHeader += '<div style="font-weight:bold;float:left;padding:3px;">Document</div>';
    newElementHtmlHeader += '<div style="font-weight:bold;float:left;padding:3px;"></div>';
    newElementHtmlHeader += '<div style="clear:both;"></div>';
    jQuery("#myInfoDivData").append(newElementHtmlHeader);

    ClientContext.executeQueryAsync(Function.createDelegate(this, function () {
        var newElementHtml;
        for (var i = 0; i < fileItems.length; i++) {
            newElementHtml = '<div style="float:left;padding:3px;width:50px;display:table-cell; vertical-align:middle; text-align:right;" id="item' + fileItems[i].get_id() + '">';
            if (fileItems[i].get_item('DocumentStatus') != 'Waiting for Approval') {
                newElementHtml += '<img src="' + ApprovalProcess.SiteCollectionUrl + '_layouts/images/mySPProject/docError.png" style="border:0px;width:15px;height:12px;" alt="Document approval error"></img>';
            }
            newElementHtml += '</div>';
            newElementHtml += '<div style="float:left;padding:3px;">' + fileItems[i].get_item('FileLeafRef') + '</div>';

            if (fileItems[i].get_item('DocumentStatus') == 'Waiting for Approval') {
                newElementHtml += '<div style="float:left;padding:3px;" id="approvalStatus' + fileItems[i].get_id() + '">';
                newElementHtml += '</div>';
            }
            else {
                newElementHtml += '<div style="float:left;padding:3px;color:#F60000;" id="approvalStatus' + fileItems[i].get_id() + '">';
                newElementHtml += 'Error: Document not in "Waiting for Approval"-State';
                newElementHtml += '</div>';
            }
            newElementHtml += '<div style="clear:both;"></div>';
            jQuery("#myInfoDivData").append(newElementHtml);
            if (fileItems[i].get_item('DocumentStatus') == 'Waiting for Approval') {
                fileItems[i].set_item('DocumentStatus', 'Approved');
                fileItems[i].update();
                docsSentToApproval[counter] = fileItems[i];
                counter++;
            }
        }
        ClientContext.executeQueryAsync(Function.createDelegate(this, function () {
            for (var i = 0; i < docsSentToApproval.length; i++) {
                jQuery('#item' + docsSentToApproval[i].get_id()).html('<img src="' + ApprovalProcess.SiteCollectionUrl + '_layouts/images/mySPProject/docApproved2.png" style="border:0px;width:15px;height:12px;" alt="Document approved"></img>');
                jQuery('#approvalStatus' + docsSentToApproval[i].get_id()).css('color', '#368131');
                jQuery('#approvalStatus' + docsSentToApproval[i].get_id()).html('Success');
                if(i == (docsSentToApproval.length - 1))
                {
                 jQuery('#myCloseInfoDivButton').removeAttr("disabled");
                 jQuery('#myLoadingBar').css('display','none');
                }
            }
        }), Function.createDelegate(this, function (sender, args) {
            // handle error somehow
        }));
    }), Function.createDelegate(this, this.onLoadItemFailure));
}

and here how it looks like:

Full Screen Layer with "PopUp"


After updating the properties of the selected documents

Maybe this is useful for someone.

LUA - native.newWebView - Showing a loading status during request

Hi guys,

here a small, but very useful code if you are programming apps in LUA with Corona SDK.
If you are using a simple native.newWebView and you want to display a status / loading bar during the request, you can use the following code:

-- show activity indicator
native.setActivityIndicator( true )
-- create the native.newWebView object
webView = native.newWebView( display.contentWidth * 0.5, 200 , display.contentWidth  * 0.5, 400 )
-- request the URL
webView:request( theURL )
-- add an event listener to the native.newWebView object
webView:addEventListener( "urlRequest", webViewListener )

-- this function will be called during the request
function webViewListener( event )
      print "Entering: webViewListener"      
      if (event.type == "loaded") then
        print("URL: "..event.url)
        native.setActivityIndicator( false )
      else
        native.setActivityIndicator( true )
      end
end