Reusable Accessible Mapping Platform

API Docs for: 5.3.1
Show:

File: src/js/RAMP/bootstrapper.js

/*global require, window, dojoConfig, i18n, document, $, console, RAMP */

/**
* Ramp module
*
* @module RAMP
* @main RAMP
*/

/**
* Bootstrapper class.
* Starting point of RAMP, RAMP modules are loaded here and mapped to a function parameter
* Phase X?: For mobile support, there can be a different mobileBootstrapper with only the mobile modules loaded
*
* ####Imports RAMP Modules:
* {{#crossLink "Map"}}{{/crossLink}}  
* {{#crossLink "BaseMapSelector"}}{{/crossLink}}  
* {{#crossLink "Maptips"}}{{/crossLink}}  
* {{#crossLink "Datagrid"}}{{/crossLink}}  
* {{#crossLink "Navigation"}}{{/crossLink}}  
* {{#crossLink "FilterManager"}}{{/crossLink}}  
* {{#crossLink "BookmarkLink"}}{{/crossLink}}  
* {{#crossLink "Url"}}{{/crossLink}}  
* {{#crossLink "FeatureHighlighter"}}{{/crossLink}}  
* {{#crossLink "RAMP"}}{{/crossLink}}  
* {{#crossLink "GlobalStorage"}}{{/crossLink}}  
* {{#crossLink "GUI"}}{{/crossLink}}  
* {{#crossLink "EventManager"}}{{/crossLink}}  
* {{#crossLink "AdvancedToolbar"}}{{/crossLink}}  
* {{#crossLink "Util"}}{{/crossLink}}  
* {{#crossLink "Prototype"}}{{/crossLink}}  
* {{#crossLink "FunctionMangler"}}{{/crossLink}}  
* {{#crossLink "LayerLoader"}}{{/crossLink}}  
* 
* @class Bootstrapper
* @static
*
* @uses dojo/parser
* @uses dojo/on
* @uses dojo/topic
* @uses dojo/request/script
* @uses dojo/request/xhr
*/

require([
/* Dojo */
    "dojo/parser", "dojo/on", "dojo/topic", "dojo/request/script", "dojo/request/xhr",
    "esri/config", "esri/urlUtils",

/* RAMP */
    "ramp/map", "ramp/basemapSelector", "ramp/maptips", "ramp/datagrid",
    "ramp/navigation", "ramp/filterManager", "ramp/imageExport", "ramp/bookmarkLink",
    "utils/url", "ramp/featureHighlighter",
    "ramp/ramp", "ramp/globalStorage", "ramp/gui", "ramp/eventManager",
    "ramp/advancedToolbar", "ramp/geoSearch",
    "ramp/theme", "ramp/layerLoader", "ramp/dataLoaderGui", "ramp/dataLoader", "ramp/stepItem",
    
/* Utils */
    "utils/util",

/* Plugins */
    "utils/prototype!", "utils/functionMangler!", "dojo/domReady!"],

    function (
    /* Dojo */
    parser, dojoOn, topic, requestScript, xhr,
    esriConfig, esriUrlUtils,

    /* RAMP */
    RampMap, BasemapSelector, Maptips, Datagrid, NavWidget, FilterManager, ImageExport,
    BookmarkLink, Url, FeatureHighlighter,
    Ramp, GlobalStorage, gui, EventManager, AdvancedToolbar, GeoSearch,
    theme, LayerLoader, DataLoadedGui, DataLoader, StepItem,

    /* Utils */
        UtilMisc
    ) {
        "use strict";

        /**
        * loadPlugin takes a plugin file and loads it into the DOM.
        * Creates a dynamic script tag to load the script at runtime.
        *
        * @method loadPlugin
        * @private
        * @param {String} pluginName, the file name of the plugin to be loaded (should be in the plugins folder)
        */
        function loadPlugin(pluginName) {
            var head = document.getElementsByTagName('head')[0],
                script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = dojoConfig.fullPluginPath + pluginName;
            console.log('loading plugin: ' + script.src);
            head.appendChild(script);
        }

        function initializeMap() {
            /* Start - RAMP Events, after map is loaded */

            // this split exists solely to separate out the parts that IE9 is
            // bad at handling there is a DOM race condition somewhere in here,
            // we've given up on trying to find it
            function guiInits() {
                //initialize the filter
                FilterManager.init();

                // Initialize the advanced toolbar and tools.
                if (RAMP.config.advancedToolbar.enabled) {
                    AdvancedToolbar.init();
                }

                Datagrid.init();
                theme.tooltipster();

                //start loading the layers
                RAMP.startupLayers.forEach(function (layer) {
                    LayerLoader.loadLayer(layer);
                });
            }

            topic.subscribe(EventManager.Map.INITIAL_BASEMAP_LOADED, function () {
                console.log("map - >> first update-end; init the rest");

                // Only initialize the bookmark link after all the UI events of all other modules have
                // finished loading
                // IMPORTANT: for now, only basemapselector and filtermanager have a UI complete event
                // but in the future, if other modules start publishing their own UI complete events, it needs
                // to be subscribe to here so BookmarkLink will not attempt to call the module before its GUI
                // has finished rendering
                UtilMisc.subscribeAll(
                    [
                        EventManager.BasemapSelector.UI_COMPLETE,
                        EventManager.FilterManager.UI_COMPLETE
                    ], function () {
                        BookmarkLink.subscribeAndUpdate();

                        //initialize the map export after everything is done
                        ImageExport.init();

                        DataLoadedGui.init();
                        //RampMap.zoomToLayerScale();
                    });
                // Added current level so slider will know how to adjust the position
                var currentLevel = (RampMap.getMap().__LOD.level) ? RampMap.getMap().__LOD.level : 0;

                NavWidget.init(currentLevel);
                FeatureHighlighter.init();

                Maptips.init();

                //Apply listeners for basemap gallery
                BasemapSelector.init();

                if (RAMP.flags.brokenWebBrowser || RAMP.flags.ie10client) {
                    console.log('delaying for IE9 and IE10 to catch up with the group');
                    window.setTimeout(guiInits, 2000);
                } else {
                    guiInits();
                }

            });

            RampMap.init();
            NavWidget.construct();

            // a workaround for bug#3460; ideally each module's ui component would call tooltipster on its own; probably a good idea would to implement this when working on mobile view
            theme.tooltipster();

            /* End - RAMP Events */
        }
        /* End - Bootstrapper functions */

        // Check to make sure the console exists, redefines it to the no-op function
        // if it does not (e.g. in IE when the debugger is not on)
        UtilMisc.checkConsole();

        // Once all of our modules are loaded and the DOM is ready:

        // call the parser to create the dijit layout dijits
        parser.parse();

        //To hold values from RAMP service

        var lang = $("html").attr("lang"),
            configFile,
            defJson;

        if (lang !== "en" && lang !== "fr") {
            lang = "en";
        }

        RAMP.locale = lang;

        i18n.init(
        {
            lng: lang + "-CA",
            load: "current",
            fallbackLng: false
        });

        //loading config object from JSON file
        configFile = (lang === "fr") ? "config.fr.json" : "config.en.json";

        // Request the JSON config file
        defJson = xhr(configFile, {
            handleAs: "json"
        });

        defJson.then(
            function (fileConfig) {
                //there is no need to convert the result to an object.  it comes through pre-parsed
                if (!RAMP.configServiceURL) {
                    //no config service.  we just use the file provided
                    configReady(fileConfig);
                } else {
                    //get additional config stuff from the config service.  mash it into our primary object

                    // pull smallkeys from URL
                    var siteURL = new Url(require.toUrl(document.location)),
                        smallkeys = siteURL.queryObject.keys;

                    if (!smallkeys || smallkeys === "") {
                        //no keys.  no point hitting the service.  jump to next step
                        configReady(fileConfig);
                    } else {
                        //TODO verify endpoint is correct
                        var serviceUrl = RAMP.configServiceURL + "docs/" + $("html").attr("lang") + "/" + smallkeys,
                            defService = requestScript.get(serviceUrl, { jsonp: 'callback', timeout: 5000 });

                        //Request the JSON snippets from the RAMP Config Service

                        //NOTE: XHR cannot be used here for cross domain purposes (primarily when running thru visual studio).
                        //      we use request/script instead to get the config as jsonp
                        //      we may consider looking into ways to mitiate the cross domain issue (Aly had some ideas)

                        defService.then(
                            function (serviceContent) {
                                console.log(serviceContent);

                                //we are expecting an array of JSON config fragments
                                //merge each fragment into the file config

                                serviceContent.forEach(function (configFragment) {
                                    UtilMisc.mergeRecursive(fileConfig, configFragment);
                                });

                                //fragments are now in fileConfig.  carry on.
                                configReady(fileConfig);
                            },
                            function (error) {
                                console.log("An error occurred: " + error);
                            }
                        );
                    }
                }
            },
            function (error) {
                console.log("An error occurred when retrieving the JSON Config: " + error);
            }
        );

        /**
        * once the config file has been retrieved, proceed with the loading of the site
        *
        * @method configReady
        * @private
        * @param {Object} configObject the configuration object
        */
        function configReady(configObject) {
            var pluginConfig,
                advancedToolbarToggle = $("li.map-toolbar-item #advanced-toggle").parent(),
                brokenWebBrowser = document.getElementsByTagName('html')[0].className.indexOf('dj_ie9') > -1,
                annoyingWebBrowser = document.getElementsByTagName('html')[0].className.indexOf('dj_ie10') > -1;

            console.log("Bootstrapper: config loaded");

            GlobalStorage.init(configObject);
            GlobalStorage.defineProjections(window.proj4);
            GeoSearch.init();

            esriConfig.defaults.io.proxyUrl = RAMP.config.proxyUrl;
            // try to avoid the proxy if possible, but this will cause network errors if CORS is not allowed by the target server
            esriConfig.defaults.io.corsDetection = !brokenWebBrowser;
                // really IE9???  (╯°□°)╯︵ ┻━┻
            if (brokenWebBrowser && RAMP.config.exportProxyUrl !== undefined) {
                esriUrlUtils.addProxyRule({ proxyUrl: RAMP.config.exportProxyUrl, urlPrefix: RAMP.config.exportMapUrl });
            }
            RAMP.flags.brokenWebBrowser = brokenWebBrowser;
            RAMP.flags.ie10client = annoyingWebBrowser;

            // Show or remove advanced toolbar toggle based on the config value
            if (RAMP.config.advancedToolbar.enabled) {
                advancedToolbarToggle.removeClass("wb-invisible");
            } else {
                advancedToolbarToggle.remove();
            }

            pluginConfig = RAMP.config.plugins;
            if (pluginConfig) {
                pluginConfig.map(function (pName) { loadPlugin(pName); });
            }

            // apply defaulting of extents (must be done prior to bookmark link updates)
            RampMap.applyExtentDefaulting();

            // Modify the config based on the url
            // needs to do this before the gui loads because the gui module
            // also reads from the config
            BookmarkLink.updateConfig(window.location.pathname.split("/").last());

            //other initilizations must wait until our extents have been projected to our active basemap
            topic.subscribe(EventManager.Map.EXTENTS_REPROJECTED, function () {
                // Initialize the map only after the gui loads
                // if we do it beforehand, the map extent may get messed up since
                // the available screen size may still be changing (e.g. due to fullscreen
                // or subpanel closing)
                topic.subscribe(EventManager.GUI.UPDATE_COMPLETE, function () {
                    // Create the panel that the bookmark link sits in
                    // can only do this after the gui loads
                    BookmarkLink.createUI();

                    LayerLoader.init();
                    initializeMap();
                });

                gui.load(null, null, function () { });
                
                Ramp.loadStrings();
            });

            //project extents to basemap
            RampMap.projectConfigExtents();
        }
    });