Common Custom tasks
Common_CustomTasks_CSharp\FindNearTask_CSharp\Resources\javascript\FindNearTask.js
 Copyright 2011 ESRI
 
 All rights reserved under the copyright laws of the United States
 and applicable international laws, treaties, and conventions.
 
 You may freely redistribute and use this sample code, with or
 without modification, provided you include the original copyright
 notice and use restrictions.
 
 See <a href="http://resourcesbeta.arcgis.com/en/help/arcobjects-net/usagerestrictions.htm">the use restrictions</a>.
 

// Global variables
var _callbackFunctionString = null;
var _selectByTaskResultActive = false;
var _selectionLayerLabel = null;
var _selectionLayerDropDownList = null;
var _searchDistanceTextBox = null;
var _unitsDropDownList = null;
var _selectByMapActive = false;
var _buddyMapID = null;
var _findButton = null;
var _activityIndicatorDiv = null;
var _activityIndicatorCallbackCount = 0;
var _buddyTaskResultsID = null;
var _featureNodeIDs = new Object();
var _mapToolActive = false;
var _activityIndicatorTimeout = null;

// Fires when a tool is selected
function toolSelected(toolbarObject, activeToolInfo)
{
    // Check whether the clicked tool is one of our custom tools
    if (activeToolInfo.tool.name == 'SearchAreaByTaskResult' && !_selectByTaskResultActive) {
        // The tool is the specify search area by task result, so we set the tracking flag accordingly
        _selectByTaskResultActive = true;

        // Add an event handler to show the area updating activity indicator when a FeatureNode
        // is clicked.
        var taskResults = $find(_buddyTaskResultsID);
        taskResults.add_nodeToggled(onTaskResultsNodeClicked);

        // Make an asyncrhonous request to the server to update FindNearTask's server-side flag storing
        // whether the SearchAreaByTaskResult tool is selected
        var argument = String.format('EventArg=toggleSelectByTaskResult&Value={0}', _selectByTaskResultActive);
        executeCallback(argument);
    }
    else if (_selectByTaskResultActive) {
        // The SearchAreaByTaskResult tool was the last tool active, so we need to toggle off the flag
        // indicating its active state
        _selectByTaskResultActive = false;        

        // Remove the handler that fires when a TaskResults node is clicked
        var taskResults = $find(_buddyTaskResultsID);
        taskResults.remove_nodeToggled(onTaskResultsNodeClicked);

        // Make an asyncrhonous request to the server to update FindNearTask's server-side flag storing
        // whether the SearchAreaByTaskResult tool is selected
        var argument = String.format('EventArg=toggleSelectByTaskResult&Value={0}', _selectByTaskResultActive);
        executeCallback(argument);
    }
    
    if (activeToolInfo.tool.name == 'SearchAreaBySelection') {
        // If the tool to specify search area by selecting features was clicked, display the drop-dwon
        // list allowing users to specify the layer from which features are to be selected
        _selectionLayerLabel.style.display = 'inline';
        _selectionLayerDropDownList.style.display = 'inline';
        _selectByMapActive = true;
    }
    else {
        // The selected tool was not the one to specify search area by selecting features, so make sure
        // the selection layer drop-down list is hidden
        _selectionLayerLabel.style.display = 'none';
        _selectionLayerDropDownList.style.display = 'none';
        _selectByMapActive = false;
    }

    // Check whether a FindNearTask tool requiring map interaction was clicked and set the flag reflecting
    // this accordingly
    if ((activeToolInfo.tool.name == 'SearchAreaByPoint') || (activeToolInfo.tool.name == 'SearchAreaByLine') ||
    (activeToolInfo.tool.name == 'SearchAreaByPolygon') || (activeToolInfo.tool.name == 'SearchAreaBySelection'))
        _mapToolActive = true;
    else
        _mapToolActive = false;
}

// Fires when the tool to specify search area by task result is active and a TaskResult node is clicked
function onTaskResultsNodeClicked(sender, eventArgs) {
    // Check the node's ID against the array storing all the IDs of FeatureNodes.  If the ID is present,
    // that means the node clicked is a FeatureNode.  Show the area updating activity indicator accordingly.
    if (_featureNodeIDs[eventArgs.nodeID])
        showUpdateAreaIndicator();
}

// Fires when the "Add New Search Areas to Previous" checkbox is clicked.  
function addToInputClicked() {
    // Issue an asynchronous request to the server to inform FindNearTask how to handle new input geometries.
    var argument = 'EventArg=toggleAddToInput';
    executeCallback(argument);
}

// Fires when the search distance or units are changed.
function updateSearchArea() {    
    // Get the search distance and units
    var searchDistance = _searchDistanceTextBox.value;
    var units = _unitsDropDownList.options[_unitsDropDownList.selectedIndex].text;
        
    // Display the area updating activity indicator
    showUpdateAreaIndicator();

    // Issue an asynchronous request to the server that will inform FindNearTask to update
    // the task buffer geometry
    var argument = String.format('EventArg=updateSearchArea&searchDistance={0}&units={1}',
        searchDistance, units);    
    executeCallback(argument);
}

// Fires when a new search layer is selected
function updateSearchLayer(element) {
    // Issue an asynchronous request to the server informing the server-side FindNearTask of 
    // the new search layer
    var argument = String.format("EventArg=updateSearchLayer&SearchLayerParameters={0}", 
        element.options[element.selectedIndex].value);
    executeCallback(argument);
}

// Displays the area updating activity indicator
function showUpdateAreaIndicator() {
    // Increment the activity indicator count.  In the event that multiple operations are
    // initiated that require displaying the activity indicator, this keeps track of how
    // many outstanding operations there are.  The activity indicator can be hidden when
    // this count reaches zerio.
    _activityIndicatorCallbackCount++;

    // Set a timeout to hide the activity indicator after two minutes.  This is done because
    // requests can occasionally get out of sync, resulting in a hanging activity indicator.
    if (_activityIndicatorTimeout)
        window.clearTimeout(_activityIndicatorTimeout);
    _activityIndicatorTimeout = window.setTimeout("resetUpdateAreaIndicator();", 120000);

    // If the activity indicator count is less than two, than the indicator is not currently
    // displayed.  Display it here.
    if (_activityIndicatorCallbackCount < 2)
    {
        _activityIndicatorDiv.style.display = 'inline';
        _findButton.style.display = 'none';
    }
}

// Hides the area updating activity indicator
function hideUpdateAreaIndicator() {
    // Decrement the activity indicator count.  See showUpdateAreaIndicator for an
    // explanation of what the counter is used for.
    _activityIndicatorCallbackCount--;
    
    // If the activity indicator count is less than one, than the indicator should be hidden.
    if (_activityIndicatorCallbackCount <= 0)
    {
        _activityIndicatorDiv.style.display = 'none';
        _findButton.style.display = 'inline';
        
        if (_activityIndicatorCallbackCount < 0)
            _activityIndicatorCallbackCount = 0;
            
        // Clear the fail-safe activity indicator timeout
        if (_activityIndicatorTimeout)
        {
            window.clearTimeout(_activityIndicatorTimeout);
            _activityIndicatorTimeout = null;
        }
    }
}

// Called if the area updating activity indicator hangs for two minutes.  Resets the
// activity indicator counter and hides the activity indicator.
function resetUpdateAreaIndicator()
{
    _activityIndicatorCallbackCount = 1;
    hideUpdateAreaIndicator();
}

// Passes the specified argument to the server via an asyncrhonous request
function executeCallback(argument)
{
    var context;
    eval(_callbackFunctionString);
}

// Checks whether the page is using callbacks or partial postbacks and specifies the method to
// handle asynchronous requests accordingly
function initAsyncRequestHandler()
{       
    // Check to see whether the Web ADF will be using the Callback or PartialPostback framework.  
    // We do this by checking for the ASP.NET AJAX client-side objects that accompany the presence
    // of a ScriptManager on the page.  Here we check for each object followed by its child object
    // because we can't be certain which objects will be present when there is not a ScriptManager
    // on the page (e.g. Sys may be present, but Sys.WebForms may not be).  But we do know that if
    // any one of the objects in the following if statement is not present, then a ScriptManger is
    // not on the page, and the Web ADF will use the Callback framework.
    if (!Sys || !Sys.WebForms || !Sys.WebForms.PageRequestManager)
    {
        // The Callback framework is being used by the Web ADF.  
        var map = $find(_buddyMapID);       
        map.add_onServerRequest(onMapCallback);
    } 
    else
    {
        var pageRequestManager = Sys.WebForms.PageRequestManager.getInstance();
        pageRequestManager.add_beginRequest(onPartialPostback);
    }
    
}   

// Fires when the map sends a request to the server
function onMapCallback(mapObject, callbackArgument) {
    // Validate the callback argument
    if (!callbackArgument.argument)
        return;
        
    var arguments = callbackArgument.argument.split('&');
    if (!arguments || arguments.length == 0)
        return;
        
    var eventArgument = arguments[0].split('=');
    
    if (eventArgument.length <= 1)
        return;
        
    // Retrieve the argument that specifies which tool initiate the request, if any
    eventArgument = eventArgument[1];
    
    if ((eventArgument == 'Point') || (eventArgument == 'Polyline') ||
    (eventArgument == 'Polygon') || (eventArgument == 'DragRectangle'))
    {
        // Check whether one of our custom tools is the currently selected tool and that the callback 
        // framework is being used.  If the callback framework is being used, then we explicitly add 
        // parameters to the page request that contain the value of server controls that we want to 
        // use to specify input sto our custom tools.  If the callback framework is not being used 
        // (meaning a ScriptManager is on the page and the AJAX framework is being used), then the 
        // values of server controls are automatically included in the page request
        if (_selectByMapActive)
        {
            // Call function to add custom arguments to the arguments being sent to the server
            callbackArgument.argument = addCustomArguments(callbackArgument.argument);
        }
        if (_mapToolActive)
            showUpdateAreaIndicator();
    }    
}

function onPartialPostback(pageRequestManager, postBackParameters)
{
    if (_selectByMapActive)
    {
        var request = postBackParameters.get_request();
        var body = request.get_body();
        request.set_body(addCustomArguments(body));
    }
    if (_mapToolActive)
        showUpdateAreaIndicator();

    hideUpdateAreaIndicator();
}

function addCustomArguments(args)
{            
    // If this function is called, that means the Callback framework is being used by the Web ADF.  
    // Since we wish to pass the value of the server-side controls to our custom tools via page 
    // request parameters, we have to explicitly add these values to the request arguments.  When
    // a partial postback is being used, this value is automatically included in the Page's request 
    // parameters.              
    
    // Add the control values to the passed-in arguments with the control IDs as keys.
    args += String.format('&SelectionLayer={0}', 
        _selectionLayerDropDownList.options[_selectionLayerDropDownList.selectedIndex].value);
    
    return args;
}