template.js

281 lines | 15.944 kB Blame History Raw Download
define(["dojo/Evented", "dojo/parser", "dojo/_base/declare", "dojo/_base/kernel", "dojo/_base/array", "dojo/_base/lang", "dojo/dom-class", "dojo/Deferred", "dojo/promise/all", "esri/arcgis/utils", "esri/urlUtils", "esri/request", "esri/config", "esri/lang", "esri/IdentityManager", "esri/tasks/GeometryService", "config/defaults", "application/OAuthHelper", "config/commonConfig"

], function (
Evented, parser, declare, kernel, array, lang, domClass, Deferred, all, arcgisUtils, urlUtils, esriRequest, esriConfig, esriLang, IdentityManager, GeometryService, defaults, OAuthHelper, commonConfig) {
    return declare([Evented], {
        config: {},
        localize: false,
        orgConfig: {},
        appConfig: {},
        constructor: function (supportsLocalization) {
            //config will contain application and user defined info for the application such as i18n strings, 
            //the web map id and application id, any url parameters and any application specific configuration
            // information. 
            this.config = declare.safeMixin(defaults, commonConfig);
            this.localize = supportsLocalization || false;
            this._init().then(lang.hitch(this, function () {
                this.emit("ready", this.config);
            }));
        },
        //Get URL parameters and set application defaults needed to query arcgis.com for
        //an application and to see if the app is running in Portal or an Org
        _init: function () {
            var deferred = new Deferred();
            //Set the web map, group and appid if they exist but ignore other url params. 
            //Additional url parameters may be defined by the application but they need to be mixed in
            //to the config object after we retrieve the application configuration info. As an example,
            //we'll mix in some commonly used url parameters in the _queryUrlParams function after
            //the application configuration has been applied so that the url parameters overwrite any
            //configured settings. It's up to the application developer to update the application to take 
            //advantage of these parameters. 
            var paramItems = ["webmap", "appid", "group", "oauthappid"];
            var mixinParams = this._createUrlParamsObject(paramItems);
            lang.mixin(this.config, mixinParams);
            //Define the sharing url and other default values like the proxy. 
            //The sharing url defines where to search for the web map and application content. The
            //default value is arcgis.com. 
            this._initializeApplication();

            this._getLocalization().then(lang.hitch(this, this._queryApplicationConfiguration)).then(lang.hitch(this, this._queryDisplayItem)).then(lang.hitch(this, this._queryOrganizationInformation)).then(lang.hitch(this, function () {


                //Now that we have the org and app settings do the mixins. First overwrite the defaults 
                //with the application settings then apply org settings if required
                lang.mixin(this.config, this.appConfig);
                if (this.config.queryForOrg !== false) {
                    lang.mixin(this.config, this.orgConfig);
                }
                //Set the geometry helper service to be the app default.  
                if (this.config.helperServices && this.config.helperServices.geometry && this.config.helperServices.geometry.url) {
                    esriConfig.defaults.geometryService = new GeometryService(this.config.helperServices.geometry.url);
                }
                //Now update the config with any custom url params
                this._queryUrlParams();

                //setup OAuth if oauth appid exists
                if (this.config.oauthappid) {
                    this._setupOAuth(this.config.oauthappid, this.config.sharinghost);
                }

                deferred.resolve();
            }));

            return deferred.promise;
        },
        _createUrlParamsObject: function (items) {
            //retrieve url parameters. Templates all use url parameters to determine which arcgis.com 
            //resource to work with. 
            //Map templates use the webmap param to define the webmap to display
            //Group templates use the group param to provide the id of the group to display. 
            //appid is the id of the application based on the template. We use this 
            //id to retrieve application specific configuration information. The configuration 
            //information will contain the values the  user selected on the template configuration 
            //panel.  
            var urlObject = urlUtils.urlToObject(document.location.href);
            urlObject.query = urlObject.query || {};
            var obj = {};
            if (urlObject.query && items && items.length) {
                for (var i = 0; i < items.length; i++) {
                    if (urlObject.query[items[i]]) {
                        obj[items[i]] = urlObject.query[items[i]];
                    }
                }
            }
            return obj;
        },

        _initializeApplication: function () {

            //Check to see if the app is hosted or a portal. If the app is hosted or a portal set the
            // sharing url and the proxy. Otherwise use the sharing url set it to arcgis.com. 
            //We know app is hosted (or portal) if it has /apps/ or /home/ in the url. 
            var appLocation = location.pathname.indexOf("/apps/");
            if (appLocation === -1) {
                appLocation = location.pathname.indexOf("/home/");
            }
            //app is hosted and no sharing url is defined so let's figure it out. 
            if (appLocation !== -1) {
                //hosted or portal
                var instance = location.pathname.substr(0, appLocation); //get the portal instance name
                //this.config.sharinghost = location.protocol + "//" + location.host + instance;
                this.config.sharinghost = location.protocol + "//" + "www.arcgis.com";
                this.config.proxyurl = location.protocol + "//" + location.host + instance + "/sharing/proxy";
            } else {
                //setup OAuth if oauth appid exists. If we don't call it here before querying for appid
                //the identity manager dialog will appear if the appid isn't publicly shared.
                if (this.config.oauthappid) {
                    this._setupOAuth(this.config.oauthappid, this.config.sharinghost);
                }
            }
            arcgisUtils.arcgisUrl = this.config.sharinghost + "/sharing/rest/content/items";
            //Define the proxy url for the app 
            if (this.config.proxyurl) {
                esriConfig.defaults.io.proxyUrl = this.config.proxyurl;
                esriConfig.defaults.io.alwaysUseProxy = false;
            }

            //check sign-in status 
            IdentityManager.checkSignInStatus(this.config.sharinghost + "/sharing").then(lang.hitch(this, function (credential) {
                return;
            }, function (error) {
                return;
            }));

        },
        _setupOAuth: function (id, portal) {
            OAuthHelper.init({
                appId: id,
                portal: portal,
                expiration: (14 * 24 * 60) //2 weeks (in minutes)
            });
        },
        _getLocalization: function () {
            var deferred = new Deferred();
            if (this.localize) {
                require(["dojo/i18n!application/nls/resources"], lang.hitch(this, function (appBundle) {
                    //Get the localization strings for the template and store in an i18n variable. Also determine if the 
                    //application is in a right-to-left language like Arabic or Hebrew. 
                    this.config.i18n = appBundle || {};
                    //Bi-directional language support added to support right-to-left languages like Arabic and Hebrew
                    //Note: The map must stay ltr  
                    this.config.i18n.direction = "ltr";
                    array.some(["ar", "he"], lang.hitch(this, function (l) {
                        if (kernel.locale.indexOf(l) !== -1) {
                            this.config.i18n.direction = "rtl";
                            return true;
                        } else {
                            return false;
                        }
                    }));
                    //add a dir attribute to the html tag. Then you can add special css classes for rtl languages
                    var dirNode = document.getElementsByTagName("html")[0];
                    var classes = dirNode.className;
                    if (this.config.i18n.direction === "rtl") {
                        //need to add support for dj_rtl. 
                        //if the dir node is set when the app loads dojo will handle. 
                        dirNode.setAttribute("dir", "rtl");
                        var rtlClasses = " esriRTL dj_rtl dijitRtl " + classes.replace(/ /g, "-rtl ");
                        dirNode.className = lang.trim(classes + rtlClasses);
                    } else {
                        dirNode.setAttribute("dir", "ltr");
                        domClass.add(dirNode, "esriLTR");
                    }
                    deferred.resolve(this.config.i18n);
                }));
            } else {
                deferred.resolve();
            }
            return deferred.promise;
        },
        _queryDisplayItem: function () {
            //Get details about the specified web map or group. If the group or web map is not shared publicly users will
            //be prompted to log-in by the Identity Manager.
            var deferred = new Deferred();
            if (this.config.webmap || this.config.group) {
                var itemId = this.config.webmap || this.config.group;
                arcgisUtils.getItem(itemId).then(lang.hitch(this, function (itemInfo) {
                    //ArcGIS.com allows you to set an application extent on the application item. Overwrite the 
                    //existing web map extent with the application item extent when set. 
                    if (this.config.appid && this.config.application_extent.length > 0 && itemInfo.item.extent) {
                        itemInfo.item.extent = [
                            [
                            parseFloat(this.config.application_extent[0][0]), parseFloat(this.config.application_extent[0][1])],
                            [
                            parseFloat(this.config.application_extent[1][0]), parseFloat(this.config.application_extent[1][1])]
                        ];
                    }
                    //Set the itemInfo config option. This can be used when calling createMap instead of the webmap or group id 
                    this.config.itemInfo = itemInfo;
                    deferred.resolve();
                }));
            } else {
                deferred.resolve();
            }
            return deferred.promise;
        },
        _queryApplicationConfiguration: function () {
            //Get the application configuration details using the application id. When the response contains
            //itemData.values then we know the app contains configuration information. We'll use these values
            //to overwrite the application defaults.
            var deferred = new Deferred();
            if (this.config.appid) {
                arcgisUtils.getItem(this.config.appid).then(lang.hitch(this, function (response) {
                    if (response.item && response.itemData && response.itemData.values) {
                        //get app config values - we'll merge them with config later. 
                        this.appConfig = response.itemData.values;

                        //Get the web map from the app values. But if there's a web url
                        //parameter don't overwrite with the app value. 
                        var webmapParam = this._createUrlParamsObject(["webmap"]);
                        if (!esriLang.isDefined(webmapParam.webmap) && response.itemData.values.webmap && this.config.webmap) {
                            this.config.webmap = response.itemData.values.webmap;
                        }
                    }
                    //get the extent for the application item. This can be used to override the default web map extent
                    if (response.item && response.item.extent) {
                        this.config.application_extent = response.item.extent;
                    }
                    deferred.resolve();
                }));
            } else {
                deferred.resolve();
            }
            return deferred.promise;
        },
        _queryOrganizationInformation: function () {
            var deferred = new Deferred();
            //Query the ArcGIS.com organization. This is defined by the sharinghost that is specified. For example if you 
            //are a member of an org you'll want to set the sharinghost to be http://<your org name>.arcgis.com. We query 
            //the organization by making a self request to the org url which returns details specific to that organization. 
            //Examples of the type of information returned are custom roles, units settings, helper services and more. 
            esriRequest({
                url: this.config.sharinghost + "/sharing/rest/portals/self",
                content: {
                    "f": "json"
                },
                callbackParamName: "callback"
            }).then(lang.hitch(this, function (response) {
                //get units defined by the org or the org user
                this.orgConfig.units = "metric";
                if (response.user && response.user.units) { //user defined units
                    this.orgConfig.units = response.user.units;
                } else if (response.units) { //org level units 
                    this.orgConfig.units = response.units;
                } else if ((response.user && response.user.region && response.user.region === "US") || (response.user && !response.user.region && response.region === "US") || (response.user && !response.user.region && !response.region) || (!response.user && response.ipCntryCode === "US") || (!response.user && !response.ipCntryCode && kernel.locale === "en-us")) {
                    // use feet/miles only for the US and if nothing is set for a user
                    this.orgConfig.units = "english";
                }
                //Get the helper servcies (routing, print, locator etc)
                this.orgConfig.helperServices = {};
                lang.mixin(this.orgConfig.helperServices, response.helperServices);


                //are any custom roles defined in the organization? 
                if (response.user && esriLang.isDefined(response.user.roleId)) {
                    if (response.user.privileges) {
                        this.orgConfig.userPrivileges = response.user.privileges;
                    }
                }


                deferred.resolve();
            }), function (error) {
                console.log(error);
                deferred.resolve();
            });
            return deferred.promise;
        },
        _queryUrlParams: function () {
            //This function demonstrates how to handle additional custom url parameters. For example 
            //if you want users to be able to specify lat/lon coordinates that define the map's center or 
            //specify an alternate basemap via a url parameter. 
            //If these options are also configurable these updates need to be added after any 
            //application default and configuration info has been applied. Currently these values 
            //(center, basemap, theme) are only here as examples and can be removed if you don't plan on 
            //supporting additional url parameters in your application. 
            var paramItems = ["center", "basemap", "theme", "extent"];
            var mixinParams = this._createUrlParamsObject(paramItems);
            lang.mixin(this.config, mixinParams);
        }
    });
});