<commit_before>const BENEFITS = [
  {
    id: 0,
    component: {
      name: 'Decal',
      render(h) {
        return h('span', [
          'Our ',
          h(
            'a',
            {
              attrs: {
                href:
                  'https://twitter.com/TexasTribune/status/1058042543273848837/photo/1',
              },
            },
            'official member decal'
          ),
        ]);
      },
    },
  },
  {
    id: 1,
    component: {
      name: 'Email',
      render(h) {
        return h('span', [
          'Behind-the-scenes access to the Texas Tribune newsroom via our monthly ',
          h(
            'a',
            {
              attrs: {
                href:
                  'https://mailchi.mp/texastribune/your-april-membersonly-newsletter-356341',
              },
            },
            'members-only newsletter'
          ),
        ]);
      },
    },
  },
  {
    id: 2,
    component: {
      name: 'Festival',
      render(h) {
        return h('span', [
          'Discounted passes to our annual ',
          h(
            'a',
            {
              attrs: {
                href: 'https://festival.texastribune.org',
              },
            },
            'Texas Tribune Festival'
          ),
        ]);
      },
    },
  },
  {
    id: 3,
    component: {
      name: 'Wall',
      render(h) {
        return h('span', [
          'Our utmost gratitude and a special place on our ',
          h(
            'a',
            {
              attrs: {
                href:
                  'https://www.texastribune.org/support-us/donors-and-members/',
              },
            },
            'growing donor wall'
          ),
        ]);
      },
    },
  },
  {
    id: 4,
    component: {
      name: 'Informed',
      render(h) {
        return h(
          'span',
          'Informed Members also receive: Quarterly stakeholder reports'
        );
      },
    },
  },
  {
    id: 5,
    component: {
      name: 'Engaged',
      render(h) {
        return h(
          'span',
          'Engaged Members also receive: Invites to exclusive events'
        );
      },
    },
  },
  {
    id: 6,
    component: {
      name: 'Involved',
      render(h) {
        return h('span', [
          'Involved Members also receive: Discounted ',
          h(
            'a',
            {
              attrs: {
                href:
                  'https://www.texastribune.org/studio-919/downtown-austin-event-space-congress/',
              },
            },
            'Studio 919'
          ),
          ' rental rates',
        ]);
      },
    },
  },
];

export default BENEFITS;
<commit_msg>shorten text<commit_after>const BENEFITS = [
  {
    id: 0,
    component: {
      name: 'Decal',
      render(h) {
        return h('span', [
          'Our ',
          h(
            'a',
            {
              attrs: {
                href:
                  'https://twitter.com/TexasTribune/status/1058042543273848837/photo/1',
              },
            },
            'official member decal'
          ),
        ]);
      },
    },
  },
  {
    id: 1,
    component: {
      name: 'Email',
      render(h) {
        return h('span', [
          'Behind-the-scenes access to our newsroom via a monthly ',
          h(
            'a',
            {
              attrs: {
                href:
                  'https://mailchi.mp/texastribune/your-april-membersonly-newsletter-356341',
              },
            },
            'members-only newsletter'
          ),
        ]);
      },
    },
  },
  {
    id: 2,
    component: {
      name: 'Festival',
      render(h) {
        return h('span', [
          'Discounted passes to our annual ',
          h(
            'a',
            {
              attrs: {
                href: 'https://festival.texastribune.org',
              },
            },
            'Texas Tribune Festival'
          ),
        ]);
      },
    },
  },
  {
    id: 3,
    component: {
      name: 'Wall',
      render(h) {
        return h('span', [
          'Our utmost gratitude and a special place on our ',
          h(
            'a',
            {
              attrs: {
                href:
                  'https://www.texastribune.org/support-us/donors-and-members/',
              },
            },
            'growing donor wall'
          ),
        ]);
      },
    },
  },
  {
    id: 4,
    component: {
      name: 'Informed',
      render(h) {
        return h(
          'span',
          'Informed Members also receive: Quarterly stakeholder reports'
        );
      },
    },
  },
  {
    id: 5,
    component: {
      name: 'Engaged',
      render(h) {
        return h(
          'span',
          'Engaged Members also receive: Invites to exclusive events'
        );
      },
    },
  },
  {
    id: 6,
    component: {
      name: 'Involved',
      render(h) {
        return h('span', [
          'Involved Members also receive: Discounted ',
          h(
            'a',
            {
              attrs: {
                href:
                  'https://www.texastribune.org/studio-919/downtown-austin-event-space-congress/',
              },
            },
            'Studio 919'
          ),
          ' rental rates',
        ]);
      },
    },
  },
];

export default BENEFITS;
<|endoftext|>


<commit_before>/**
 * Created by swhite on 2/25/14.
 */

var URLS = {
    'USER':                '/api/repository/user/',
    'USER_PERMISSIONS':    '/api/repository/permissions/',
    'PROJECTS':            '/api/repository/projects/',
    'PROJECT_USERS':       '/api/repository/projects/:id/users/',
    'MARKERS':             '/api/repository/markers/',
    'FLUOROCHROMES':       '/api/repository/fluorochromes/',
    'SPECIMENS':           '/api/repository/specimens/',
    'SUBJECT_GROUPS':      '/api/repository/subject_groups/',
    'SITES':               '/api/repository/sites/',
    'SUBJECTS':            '/api/repository/subjects/',
    'PANEL_TEMPLATES':     '/api/repository/panel_templates/',
    'SITE_PANELS':         '/api/repository/site_panels/',
    'CYTOMETERS':          '/api/repository/cytometers/',
    'COMPENSATIONS':       '/api/repository/compensations/',
    'STIMULATIONS':        '/api/repository/stimulations/',
    'SAMPLES':             '/api/repository/samples/',
    'CREATE_SAMPLES':      '/api/repository/samples/add/',
    'SAMPLE_METADATA':     '/api/repository/samplemetadata/',
    'SAMPLE_COLLECTIONS':  '/api/repository/sample_collections/',
    'SAMPLE_COLLECTION_MEMBERS':  '/api/repository/sample_collection_members/',
    'BEAD_SAMPLES':        '/api/repository/beads/',
    'VISIT_TYPES':         '/api/repository/visit_types/',
    'PARAMETER_FUNCTIONS': '/api/repository/parameter_functions/',
    'PARAMETER_VALUE_TYPES': '/api/repository/parameter_value_types/',

    // Process related API URLs
    'WORKERS':                 '/api/repository/workers/',
    'SUBPROCESS_CATEGORIES':      '/api/repository/subprocess_categories/',
    'SUBPROCESS_IMPLEMENTATIONS': '/api/repository/subprocess_implementations/',
    'SUBPROCESS_INPUTS':          '/api/repository/subprocess_inputs/',
    'VERIFY_WORKER':           '/api/repository/verify_worker/',
    'PROCESS_REQUESTS':        '/api/repository/process_requests/',
    'PROCESS_REQUEST_INPUTS':     '/api/repository/process_request_inputs',
    'PROCESS_REQUEST_OUTPUTS':     '/api/repository/process_request_outputs',
    'VIABLE_PROCESS_REQUESTS': '/api/repository/viable_process_requests/',
    'CREATE_PROCESS_REQUEST_OUTPUT':  '/api/repository/process_request_outputs/add/'
};

var service = angular.module('ReFlowApp');

service
    .factory('User', ['$resource', function ($resource) {
        var User = $resource(
            URLS.USER + ':username',
            {
                username: '@username'
            },
            {
                is_user: {method: 'GET'}
            }
        );

        return User;
    }])
    .factory('UserPermissions', ['$resource', function ($resource) {
        return $resource(URLS.USER_PERMISSIONS + ':id');
    }])
    .factory('Project', ['$resource', function ($resource) {
        var Project = $resource(
            URLS.PROJECTS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        Project.prototype.getUserPermissions = function() {
            var perms = $resource(
                URLS.PROJECTS + this.id + '/permissions/',
                {},
                {
                    get: {
                        isArray: false
                    }
                }
            );
            return perms.get();
        };

        return Project;
    }])
    .factory('ProjectUser', ['$resource', function ($resource) {
        var ProjectUser = $resource(
            URLS.PROJECT_USERS,
            {},
            {
                get: { isArray: false },
                update: { method: 'PUT' }
            }
        );

        return ProjectUser;
    }])
    .factory('Site', ['$resource', function ($resource) {
        var Site = $resource(
            URLS.SITES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        Site.prototype.getUserPermissions = function() {
            var perms = $resource(
                URLS.SITES + this.id + '/permissions/',
                {},
                {
                    get: {
                        isArray: false
                    }
                }
            );
            return perms.get();
        };

        return Site;
    }])
    .factory('Marker', ['$resource', function ($resource) {
        var Marker = $resource(
            URLS.MARKERS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Marker;
    }])
    .factory('Fluorochrome', ['$resource', function ($resource) {
        var Fluorochrome = $resource(
            URLS.FLUOROCHROMES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Fluorochrome;
    }])
    .factory('Specimen', ['$resource', function ($resource) {
        var Specimen = $resource(
            URLS.SPECIMENS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Specimen;
    }])
    .factory('Worker', ['$resource', function ($resource) {
        var Worker = $resource(
            URLS.WORKERS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Worker;
    }])
    .factory('SubjectGroup', ['$resource', function ($resource) {
        var SubjectGroup = $resource(
            URLS.SUBJECT_GROUPS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return SubjectGroup;
    }])
    .factory('Subject', ['$resource', function ($resource) {
        var Subject = $resource(
            URLS.SUBJECTS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Subject;
    }])
    .factory('VisitType', ['$resource', function ($resource) {
        var VisitType = $resource(
            URLS.VISIT_TYPES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return VisitType;
    }])
    .factory('Stimulation', ['$resource', function ($resource) {
        var Stimulation = $resource(
            URLS.STIMULATIONS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Stimulation;
    }])
    .factory('Cytometer', ['$resource', function ($resource) {
        var Cytometer = $resource(
            URLS.CYTOMETERS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Cytometer;
    }])
    .factory('PanelTemplate', ['$resource', function ($resource) {
        return $resource(
            URLS.PANEL_TEMPLATES + ':id',
            {},
            {
                update: {
                    method: 'PUT'
                }
            }
        );
    }])
    .factory('SitePanel', ['$resource', function ($resource) {
        var SitePanel = $resource(
            URLS.SITE_PANELS + ':id',
            {},
            {
                get: { isArray: false },
                query: { url: URLS.SITE_PANELS, isArray: true }
            }
        );

        return SitePanel;
    }])
    .factory('Compensation', ['$resource', function ($resource) {
        return $resource(URLS.COMPENSATIONS + ':id');
    }])
    .factory('Sample', ['$resource', function ($resource) {
        var Sample = $resource(
            URLS.SAMPLES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Sample;
    }])
    .factory('SampleCollection', ['$resource', function ($resource) {
        return $resource(URLS.SAMPLE_COLLECTIONS);
    }])
    .factory('SampleCollectionMember', ['$resource', function ($resource) {
        return $resource(
            URLS.SAMPLE_COLLECTION_MEMBERS,
            {},
            {
                save: {
                    method: 'POST',
                    isArray: true
                }
            }
        );
    }])
    .factory('BeadSample', ['$resource', function ($resource) {
        var BeadSample = $resource(
            URLS.BEAD_SAMPLES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return BeadSample;
    }])
    .factory('SubprocessCategory', ['$resource', function ($resource) {
        return $resource(URLS.SUBPROCESS_CATEGORIES);
    }])
    .factory('SubprocessImplementation', ['$resource', function ($resource) {
        return $resource(URLS.SUBPROCESS_IMPLEMENTATIONS);
    }])
    .factory('SubprocessInput', ['$resource', function ($resource) {
        return $resource(URLS.SUBPROCESS_INPUTS);
    }])
    .factory('ProcessRequest', ['$resource', function ($resource) {
        var ProcessRequest = $resource(
            URLS.PROCESS_REQUESTS + ':id',
            {},
            {
                get: { isArray: false },
            }
        );

        return ProcessRequest;
    }])
    .factory('ProcessRequestInput', ['$resource', function ($resource) {
        return $resource(
            URLS.PROCESS_REQUEST_INPUTS,
            {},
            {
                save: {
                    method: 'POST',
                    isArray: true
                }
            }
        );
    }])
    .factory('ProcessRequestOutput', ['$resource', function ($resource) {
        return $resource(URLS.PROCESS_REQUEST_OUTPUTS);
    }])
    .factory('ParameterFunction', ['$resource', function ($resource) {
        return $resource(URLS.PARAMETER_FUNCTIONS);
    }])
    .factory('ParameterValueType', ['$resource', function ($resource) {
        return $resource(URLS.PARAMETER_VALUE_TYPES);
    }])
    .service('Pretreatment', [ function () {
        this.query = function () {
            return [{name:'In vitro'}, {name:'Ex vivo'}];
        };
    }])
    .service('Storage', [ function () {
        this.query = function () {
            return [{name:'Fresh'}, {name:'Cryopreserved'}];
        };
    }]);<commit_msg>add SampleCluster to reflowService<commit_after>/**
 * Created by swhite on 2/25/14.
 */

var URLS = {
    'USER':                '/api/repository/user/',
    'USER_PERMISSIONS':    '/api/repository/permissions/',
    'PROJECTS':            '/api/repository/projects/',
    'PROJECT_USERS':       '/api/repository/projects/:id/users/',
    'MARKERS':             '/api/repository/markers/',
    'FLUOROCHROMES':       '/api/repository/fluorochromes/',
    'SPECIMENS':           '/api/repository/specimens/',
    'SUBJECT_GROUPS':      '/api/repository/subject_groups/',
    'SITES':               '/api/repository/sites/',
    'SUBJECTS':            '/api/repository/subjects/',
    'PANEL_TEMPLATES':     '/api/repository/panel_templates/',
    'SITE_PANELS':         '/api/repository/site_panels/',
    'CYTOMETERS':          '/api/repository/cytometers/',
    'COMPENSATIONS':       '/api/repository/compensations/',
    'STIMULATIONS':        '/api/repository/stimulations/',
    'SAMPLES':             '/api/repository/samples/',
    'CREATE_SAMPLES':      '/api/repository/samples/add/',
    'SAMPLE_METADATA':     '/api/repository/samplemetadata/',
    'SAMPLE_COLLECTIONS':  '/api/repository/sample_collections/',
    'SAMPLE_COLLECTION_MEMBERS':  '/api/repository/sample_collection_members/',
    'BEAD_SAMPLES':        '/api/repository/beads/',
    'VISIT_TYPES':         '/api/repository/visit_types/',
    'PARAMETER_FUNCTIONS': '/api/repository/parameter_functions/',
    'PARAMETER_VALUE_TYPES': '/api/repository/parameter_value_types/',

    // Process related API URLs
    'WORKERS':                 '/api/repository/workers/',
    'SUBPROCESS_CATEGORIES':      '/api/repository/subprocess_categories/',
    'SUBPROCESS_IMPLEMENTATIONS': '/api/repository/subprocess_implementations/',
    'SUBPROCESS_INPUTS':          '/api/repository/subprocess_inputs/',
    'VERIFY_WORKER':           '/api/repository/verify_worker/',
    'PROCESS_REQUESTS':        '/api/repository/process_requests/',
    'PROCESS_REQUEST_INPUTS':     '/api/repository/process_request_inputs',
    'PROCESS_REQUEST_OUTPUTS':     '/api/repository/process_request_outputs',
    'VIABLE_PROCESS_REQUESTS': '/api/repository/viable_process_requests/',
    'CREATE_PROCESS_REQUEST_OUTPUT':  '/api/repository/process_request_outputs/add/',
    'SAMPLE_CLUSTERS':  '/api/repository/sample_clusters/'
};

var service = angular.module('ReFlowApp');

service
    .factory('User', ['$resource', function ($resource) {
        var User = $resource(
            URLS.USER + ':username',
            {
                username: '@username'
            },
            {
                is_user: {method: 'GET'}
            }
        );

        return User;
    }])
    .factory('UserPermissions', ['$resource', function ($resource) {
        return $resource(URLS.USER_PERMISSIONS + ':id');
    }])
    .factory('Project', ['$resource', function ($resource) {
        var Project = $resource(
            URLS.PROJECTS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        Project.prototype.getUserPermissions = function() {
            var perms = $resource(
                URLS.PROJECTS + this.id + '/permissions/',
                {},
                {
                    get: {
                        isArray: false
                    }
                }
            );
            return perms.get();
        };

        return Project;
    }])
    .factory('ProjectUser', ['$resource', function ($resource) {
        var ProjectUser = $resource(
            URLS.PROJECT_USERS,
            {},
            {
                get: { isArray: false },
                update: { method: 'PUT' }
            }
        );

        return ProjectUser;
    }])
    .factory('Site', ['$resource', function ($resource) {
        var Site = $resource(
            URLS.SITES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        Site.prototype.getUserPermissions = function() {
            var perms = $resource(
                URLS.SITES + this.id + '/permissions/',
                {},
                {
                    get: {
                        isArray: false
                    }
                }
            );
            return perms.get();
        };

        return Site;
    }])
    .factory('Marker', ['$resource', function ($resource) {
        var Marker = $resource(
            URLS.MARKERS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Marker;
    }])
    .factory('Fluorochrome', ['$resource', function ($resource) {
        var Fluorochrome = $resource(
            URLS.FLUOROCHROMES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Fluorochrome;
    }])
    .factory('Specimen', ['$resource', function ($resource) {
        var Specimen = $resource(
            URLS.SPECIMENS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Specimen;
    }])
    .factory('Worker', ['$resource', function ($resource) {
        var Worker = $resource(
            URLS.WORKERS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Worker;
    }])
    .factory('SubjectGroup', ['$resource', function ($resource) {
        var SubjectGroup = $resource(
            URLS.SUBJECT_GROUPS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return SubjectGroup;
    }])
    .factory('Subject', ['$resource', function ($resource) {
        var Subject = $resource(
            URLS.SUBJECTS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Subject;
    }])
    .factory('VisitType', ['$resource', function ($resource) {
        var VisitType = $resource(
            URLS.VISIT_TYPES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return VisitType;
    }])
    .factory('Stimulation', ['$resource', function ($resource) {
        var Stimulation = $resource(
            URLS.STIMULATIONS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Stimulation;
    }])
    .factory('Cytometer', ['$resource', function ($resource) {
        var Cytometer = $resource(
            URLS.CYTOMETERS + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Cytometer;
    }])
    .factory('PanelTemplate', ['$resource', function ($resource) {
        return $resource(
            URLS.PANEL_TEMPLATES + ':id',
            {},
            {
                update: {
                    method: 'PUT'
                }
            }
        );
    }])
    .factory('SitePanel', ['$resource', function ($resource) {
        var SitePanel = $resource(
            URLS.SITE_PANELS + ':id',
            {},
            {
                get: { isArray: false },
                query: { url: URLS.SITE_PANELS, isArray: true }
            }
        );

        return SitePanel;
    }])
    .factory('Compensation', ['$resource', function ($resource) {
        return $resource(URLS.COMPENSATIONS + ':id');
    }])
    .factory('Sample', ['$resource', function ($resource) {
        var Sample = $resource(
            URLS.SAMPLES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return Sample;
    }])
    .factory('SampleCollection', ['$resource', function ($resource) {
        return $resource(URLS.SAMPLE_COLLECTIONS);
    }])
    .factory('SampleCollectionMember', ['$resource', function ($resource) {
        return $resource(
            URLS.SAMPLE_COLLECTION_MEMBERS,
            {},
            {
                save: {
                    method: 'POST',
                    isArray: true
                }
            }
        );
    }])
    .factory('BeadSample', ['$resource', function ($resource) {
        var BeadSample = $resource(
            URLS.BEAD_SAMPLES + ':id',
            {},
            {
                update: { method: 'PUT' }
            }
        );

        return BeadSample;
    }])
    .factory('SubprocessCategory', ['$resource', function ($resource) {
        return $resource(URLS.SUBPROCESS_CATEGORIES);
    }])
    .factory('SubprocessImplementation', ['$resource', function ($resource) {
        return $resource(URLS.SUBPROCESS_IMPLEMENTATIONS);
    }])
    .factory('SubprocessInput', ['$resource', function ($resource) {
        return $resource(URLS.SUBPROCESS_INPUTS);
    }])
    .factory('ProcessRequest', ['$resource', function ($resource) {
        var ProcessRequest = $resource(
            URLS.PROCESS_REQUESTS + ':id',
            {},
            {
                get: { isArray: false },
            }
        );

        return ProcessRequest;
    }])
    .factory('ProcessRequestInput', ['$resource', function ($resource) {
        return $resource(
            URLS.PROCESS_REQUEST_INPUTS,
            {},
            {
                save: {
                    method: 'POST',
                    isArray: true
                }
            }
        );
    }])
    .factory('ProcessRequestOutput', ['$resource', function ($resource) {
        return $resource(URLS.PROCESS_REQUEST_OUTPUTS);
    }])
    .factory('SampleCluster', ['$resource', function ($resource) {
        return $resource(URLS.SAMPLE_CLUSTERS);
    }])
    .factory('ParameterFunction', ['$resource', function ($resource) {
        return $resource(URLS.PARAMETER_FUNCTIONS);
    }])
    .factory('ParameterValueType', ['$resource', function ($resource) {
        return $resource(URLS.PARAMETER_VALUE_TYPES);
    }])
    .service('Pretreatment', [ function () {
        this.query = function () {
            return [{name:'In vitro'}, {name:'Ex vivo'}];
        };
    }])
    .service('Storage', [ function () {
        this.query = function () {
            return [{name:'Fresh'}, {name:'Cryopreserved'}];
        };
    }]);<|endoftext|>


<commit_before>define([
    "dojo/on",
    "dojo/dom",
    "dojo/query",
    "dojo/topic",
    "dojo/dom-class",
    "dojo/dom-style",
    "dijit/registry",
    "dojo/_base/array",
    "dojo/dom-geometry",
    "dojo/number",
    "map/config",
    "map/Map",
    "map/Finder",
    "map/MapModel",
    "utils/Hasher",
    "utils/Animator",
    "esri/geometry/webMercatorUtils",
    "esri/geometry/Point",
    "map/Controls",
    "map/LayerController",
    "analysis/WizardHelper",
    "components/LayerList",
    "utils/Loader"
], function(on, dom, dojoQuery, topic, domClass, domStyle, registry, arrayUtils, domGeom, number, MapConfig, Map, Finder, MapModel, Hasher, Animator, webMercatorUtils, Point, MapControl, LayerController, WizardHelper, LayerList, Loader) {
    'use strict';

    var initialized = false,
        mapModel,
        layerList,
        dataDivLoaded = false,
        map;
    var infoDiv = document.createElement("infoDiv");

    return {

        /* NOTE : Set Default Layers in renderComponents at the bottom of the page,
							Hash needs to be updated before the LayerList is created */

        init: function(template) {

            var self = this,
                ids = [];

            if (initialized) {
                registry.byId("stackContainer").selectChild("mapView");
                return;
            }

            initialized = true;
            registry.byId("mapView").set('content', template);
            registry.byId("stackContainer").selectChild("mapView");

            // This is not esri map, it is custom map class, esri map object available as map.map
            map = new Map(MapConfig.mapOptions);

            // Set the map object to the global app variable for easy use throughout the project
            app.map = map.map;

            map.on("map-ready", function() {
                // Bind the Model to the Map Panel, and then again to the list in the header
                var extent = webMercatorUtils.webMercatorToGeographic(map.map.extent);
                var x = number.round(extent.getCenter().x, 2);
                var y = number.round(extent.getCenter().y, 2);

                Hasher.setHash('x', x);
                Hasher.setHash('y', y);
                Hasher.setHash('l', 5);

                mapModel = MapModel.initialize("map-container");
                // Render any React Components - These will activate any default or hashed layers
                // Only use this after the map has been loaded,
                // Also call other functions in renderComponents that build UI elements
                self.renderComponents();
                // Connect Events
                self.bindUIEvents();
                //window.location.hash += '#food';
            });

            // Set up zoom listener for Protected Areas Layer *and now Gain Layer
            app.map.on('zoom-end', LayerController.checkZoomDependentLayers.bind(LayerController));

            // Set up Click Listener to Perform Identify
            app.map.on('click', Finder.performIdentify.bind(Finder));

            // Have the Finder create any formatter functions necessary for info window content
            // and then have it setup info window specific listeners for specific info windows with buttons
            Finder.createFormattingFunctions();
            Finder.setupInfowindowListeners();

            // Fade in the map controls, first, get a list of the ids
            dojoQuery(".gfw .map-layer-controls li").forEach(function(item) {
                ids.push(item.id);
            });
            // FadeIn fades opacity from current opacity to 1
            Animator.fadeIn(ids, {
                duration: 100
            });

            // Initialize Add This
            addthis.init();

        },

        bindUIEvents: function() {

            var self = this;

            on(app.map, "mouse-move", function(evt) {
                MapModel.set('currentLatitude', evt.mapPoint.getLatitude().toFixed(4));
                MapModel.set('currentLongitude', evt.mapPoint.getLongitude().toFixed(4));
            });

            on(app.map, "extent-change", function(e) {
                var delta = e.delta;
                var extent = webMercatorUtils.webMercatorToGeographic(e.extent);
                var levelChange = e.levelChange;
                var lod = e.lod;
                var map = e.target;

                var x = number.round(extent.getCenter().x, 2);
                var y = number.round(extent.getCenter().y, 2);

                Hasher.setHash('x', x);
                Hasher.setHash('y', y);
                Hasher.setHash('l', lod.level);

                // Hasher.setHash({
                //     x: x,
                //     y: y,
                //     l: lod.level
                // });
            });

            on(dom.byId("locator-widget-button"), "click", function() {
                MapModel.set('showBasemapGallery', false);
                MapModel.set('showSharingOptions', false);
                MapModel.set('showLocatorOptions', !MapModel.get('showLocatorOptions'));
            });

            on(dom.byId("basemap-gallery-button"), "click", function() {
                MapModel.set('showLocatorOptions', false);
                MapModel.set('showSharingOptions', false);
                MapModel.set('showBasemapGallery', !MapModel.get('showBasemapGallery'));
            });

            on(dom.byId("share-button"), "click", function() {
                MapModel.set('showLocatorOptions', false);
                MapModel.set('showBasemapGallery', false);
                MapModel.set('showSharingOptions', !MapModel.get('showSharingOptions'));
            });

            on(dom.byId("dms-search"), "change", function(evt) {
                var checked = evt.target ? evt.target.checked : evt.srcElement.checked;
                if (checked) {
                    MapModel.set('showDMSInputs', true);
                    MapModel.set('showLatLongInputs', false);
                }
            });

            on(dom.byId("lat-long-search"), "change", function(evt) {
                var checked = evt.target ? evt.target.checked : evt.srcElement.checked;
                if (checked) {
                    MapModel.set('showDMSInputs', false);
                    MapModel.set('showLatLongInputs', true);
                }
            });

            on(dom.byId("search-option-go-button"), "click", function() {
                Finder.searchAreaByCoordinates();
            });

            on(dom.byId("clear-search-pins"), "click", function() {
                map.map.graphics.clear();
                MapModel.set('showClearPinsOption', false);
            });

            dojoQuery(".map-layer-controls li").forEach(function(node) {
                on(node, "mouseover", function(evt) {
                    self.toggleLayerList(node);
                });
            });

            on(dom.byId("master-layer-list"), "mouseleave", function() {
                domStyle.set("master-layer-list", "opacity", 0.0);
                domStyle.set("master-layer-list", "left", '-1000px');
            });

            dojoQuery(".fires_toolbox .toolbox-list li").forEach(function(node) {
                on(node, "click", MapControl.toggleFiresLayerOptions);
            });

            on(dom.byId("high-confidence"), "change", MapControl.toggleFiresConfidenceLevel);

            dojoQuery(".gfw .overlays-container .overlays-checkbox").forEach(function(node) {
                on(node, "click", MapControl.toggleOverlays);
            });

            on(dom.byId("legend-title"), "click", function() {
                MapControl.toggleLegendContainer();
            });

            on(dom.byId("reset-suitability"), "click", function() {
                MapControl.resetSuitabilitySettings();
            });

            on(dom.byId("close-suitability"), "click", function() {
                // Pass in the key from the MapConfig.LayerUI
                // for Custom Suitability Layer
                self.toggleItemInLayerList('suit');
            });

            on(dom.byId("wizard-tab"), "click", function() {
                WizardHelper.toggleWizard();
            });

            // Click info icon in suitabiliyy tools container for all sliders
            dojoQuery('.suitability-accordion .slider-name .layer-info-icon').forEach(function(node) {
                on(node, 'click', function(evt) {
                    var target = evt.target ? evt.target : evt.srcElement,
                        dataClass = target.dataset ? target.dataset.class : target.getAttribute('data-class');
                    self.showInfoPanel(dataClass);
                });
            });

            // Click info icon in suitabiliyy tools container for Headers of sections of checkboxes
            dojoQuery('.suitability-accordion .criteria-separator .layer-info-icon').forEach(function(node) {
                on(node, 'click', function(evt) {
                    var target = evt.target ? evt.target : evt.srcElement,
                        dataClass = target.dataset ? target.dataset.class : target.getAttribute('data-class');
                    self.showInfoPanel(dataClass);
                });
            });

        },

        toggleLayerList: function(el) {
            var filter = el.dataset ? el.dataset.filter : el.getAttribute('data-filter'),
                newclass = el.dataset ? el.dataset.class : el.getAttribute('data-class'),
                position = domGeom.position(el, true),
                containerWidth = 180,
                offset;

            // 200 is the default width of the container, to keep it centered, update containerWidth
            offset = (position.w - containerWidth) / 2;
            domStyle.set("master-layer-list", "left", (position.x + offset) + "px");

            // Show the Container
            Animator.fadeIn("master-layer-list", {
                duration: 100
            });
            // Add the Appropriate Class so the Items display correct color, styling etc.
            domClass.remove("master-layer-list");
            domClass.add("master-layer-list", newclass);

            // Update the list, reuse the title from the first anchor tag in the element (el)
            if (layerList) {
                layerList.setProps({
                    title: el.children[0].innerHTML,
                    filter: filter
                });
            }
        },

        renderComponents: function() {

            // Set Default Layers Here if none are present in the URL
            // Current Default Layers(lyrs) are tcc and loss
            var state = Hasher.getHash();
            // If state.lyrs is undefined, set hash, otherwise, load the layers already there
            if (state.lyrs === undefined) {
                Hasher.toggleLayers('tcc');
                Hasher.toggleLayers('loss');
            }

            MapControl.generateSuitabilitySliders();

            layerList = new LayerList({
                items: MapConfig.layersUI
            }, "master-layer-list");

            MapControl.generateTimeSliders();

        },

        toggleItemInLayerList: function(key) {
            layerList.toggleFormElement(key);
        },

        centerChange: function(x, y, zoom) {
            //debugger;
            //console.log("center change");
            //console.log(o.map);
            //compare current center and change if different
            if (!initialized) {
                return; //map not initialized yet
            }
            var currentExtent = webMercatorUtils.webMercatorToGeographic(map.map.extent);

            var extent = webMercatorUtils.webMercatorToGeographic(map.map.extent);
            var x = number.round(extent.getCenter().x, 2);
            var y = number.round(extent.getCenter().y, 2);
            var l = map.map.getLevel();

            // Hasher.setHash('x', x);
            // Hasher.setHash('y', y);
            // Hasher.setHash('l', 5);
            //var newState = HashController.newState;
            console.log(Hasher.getHash());
            var state = Hasher.getHash();

            // Hasher.toggleLayers('tcc');
            // Hasher.toggleLayers('loss');

            var centerChangeByUrl = ((parseFloat(state.x) != x) || (parseFloat(state.y) != y) || (parseInt(state.l) != l));
            console.log(centerChangeByUrl + " " + state.y + " " + state.x);
            if (centerChangeByUrl) {
                //o.mapExtentPausable.pause();
                // on.once(map.map, "extent-change", function() {
                //     o.mapExtentPausable.resume();
                // });
                var ptWM = webMercatorUtils.geographicToWebMercator(new Point(parseFloat(state.x), parseFloat(state.y)));

                map.map.centerAndZoom(ptWM, parseInt(state.l));

                // Hasher.setHash(x, xValue);
                // Hasher.setHash(y, yValue);
            }
        },

        showInfoPanel: function(infoPanelClass) {
            if (typeof(infoPanelClass) === 'object') {
                var content = infoPanelClass;
                MapControl.createDialogBox(content);
            } else {
                if (dataDivLoaded) {
                    var content = infoDiv.querySelector("." + infoPanelClass);
                    MapControl.createDialogBox(content);
                } else {
                    Loader.getTemplate("data").then(function(template) {
                        dataDivLoaded = true;
                        infoDiv.innerHTML = template;
                        var content = infoDiv.querySelector("." + infoPanelClass);
                        MapControl.createDialogBox(content);
                    })
                }
            }
        }
    };

});<commit_msg>Restore map center & level when sharing url<commit_after>define([
    "dojo/on",
    "dojo/dom",
    "dojo/query",
    "dojo/topic",
    "dojo/dom-class",
    "dojo/dom-style",
    "dijit/registry",
    "dojo/_base/array",
    "dojo/dom-geometry",
    "dojo/number",
    "map/config",
    "map/Map",
    "map/Finder",
    "map/MapModel",
    "utils/Hasher",
    "utils/Animator",
    "esri/geometry/webMercatorUtils",
    "esri/geometry/Point",
    "map/Controls",
    "map/LayerController",
    "analysis/WizardHelper",
    "components/LayerList",
    "utils/Loader"
], function(on, dom, dojoQuery, topic, domClass, domStyle, registry, arrayUtils, domGeom, number, MapConfig, Map, Finder, MapModel, Hasher, Animator, webMercatorUtils, Point, MapControl, LayerController, WizardHelper, LayerList, Loader) {
    'use strict';

    var initialized = false,
        mapModel,
        layerList,
        dataDivLoaded = false,
        map;
    var infoDiv = document.createElement("infoDiv");

    return {

        /* NOTE : Set Default Layers in renderComponents at the bottom of the page,
							Hash needs to be updated before the LayerList is created */

        init: function(template) {

            var self = this,
                ids = [];

            if (initialized) {
                registry.byId("stackContainer").selectChild("mapView");
                return;
            }

            initialized = true;
            registry.byId("mapView").set('content', template);
            registry.byId("stackContainer").selectChild("mapView");

            // 20141222 CRB - Added restoring of map center & level when sharing url
            var hashX =  Hasher.getHash('x');
            var hashY =  Hasher.getHash('y');
            var hashL =  Hasher.getHash('l');
            //console.log("**********************> map settings in hash: " + hashX + "/" + hashY + "/" + hashL);
            var mapOptions = {};
            for (var prop in MapConfig.mapOptions) {
                mapOptions[prop] = MapConfig.mapOptions[prop];
            }
            if (hashX != undefined && hashX != "") mapOptions.centerX = hashX;
            if (hashX != undefined && hashX != "") mapOptions.centerY = hashY;
            if (hashX != undefined && hashX != "") mapOptions.zoom = hashL;
            //console.log("**********************> map options:", mapOptions);

            // This is not esri map, it is custom map class, esri map object available as map.map
            //map = new Map(MapConfig.mapOptions);
            map = new Map(mapOptions);

            // Set the map object to the global app variable for easy use throughout the project
            app.map = map.map;

            map.on("map-ready", function() {
                // Bind the Model to the Map Panel, and then again to the list in the header
                var extent = webMercatorUtils.webMercatorToGeographic(map.map.extent);
                var x = number.round(extent.getCenter().x, 2);
                var y = number.round(extent.getCenter().y, 2);

                Hasher.setHash('x', x);
                Hasher.setHash('y', y);
                Hasher.setHash('l', 5);

                mapModel = MapModel.initialize("map-container");
                // Render any React Components - These will activate any default or hashed layers
                // Only use this after the map has been loaded,
                // Also call other functions in renderComponents that build UI elements
                self.renderComponents();
                // Connect Events
                self.bindUIEvents();
                //window.location.hash += '#food';
            });

            // Set up zoom listener for Protected Areas Layer *and now Gain Layer
            app.map.on('zoom-end', LayerController.checkZoomDependentLayers.bind(LayerController));

            // Set up Click Listener to Perform Identify
            app.map.on('click', Finder.performIdentify.bind(Finder));

            // Have the Finder create any formatter functions necessary for info window content
            // and then have it setup info window specific listeners for specific info windows with buttons
            Finder.createFormattingFunctions();
            Finder.setupInfowindowListeners();

            // Fade in the map controls, first, get a list of the ids
            dojoQuery(".gfw .map-layer-controls li").forEach(function(item) {
                ids.push(item.id);
            });
            // FadeIn fades opacity from current opacity to 1
            Animator.fadeIn(ids, {
                duration: 100
            });

            // Initialize Add This
            addthis.init();

        },

        bindUIEvents: function() {

            var self = this;

            on(app.map, "mouse-move", function(evt) {
                MapModel.set('currentLatitude', evt.mapPoint.getLatitude().toFixed(4));
                MapModel.set('currentLongitude', evt.mapPoint.getLongitude().toFixed(4));
            });

            on(app.map, "extent-change", function(e) {
                var delta = e.delta;
                var extent = webMercatorUtils.webMercatorToGeographic(e.extent);
                var levelChange = e.levelChange;
                var lod = e.lod;
                var map = e.target;

                var x = number.round(extent.getCenter().x, 2);
                var y = number.round(extent.getCenter().y, 2);

                Hasher.setHash('x', x);
                Hasher.setHash('y', y);
                Hasher.setHash('l', lod.level);

                // Hasher.setHash({
                //     x: x,
                //     y: y,
                //     l: lod.level
                // });
            });

            on(dom.byId("locator-widget-button"), "click", function() {
                MapModel.set('showBasemapGallery', false);
                MapModel.set('showSharingOptions', false);
                MapModel.set('showLocatorOptions', !MapModel.get('showLocatorOptions'));
            });

            on(dom.byId("basemap-gallery-button"), "click", function() {
                MapModel.set('showLocatorOptions', false);
                MapModel.set('showSharingOptions', false);
                MapModel.set('showBasemapGallery', !MapModel.get('showBasemapGallery'));
            });

            on(dom.byId("share-button"), "click", function() {
                MapModel.set('showLocatorOptions', false);
                MapModel.set('showBasemapGallery', false);
                MapModel.set('showSharingOptions', !MapModel.get('showSharingOptions'));
            });

            on(dom.byId("dms-search"), "change", function(evt) {
                var checked = evt.target ? evt.target.checked : evt.srcElement.checked;
                if (checked) {
                    MapModel.set('showDMSInputs', true);
                    MapModel.set('showLatLongInputs', false);
                }
            });

            on(dom.byId("lat-long-search"), "change", function(evt) {
                var checked = evt.target ? evt.target.checked : evt.srcElement.checked;
                if (checked) {
                    MapModel.set('showDMSInputs', false);
                    MapModel.set('showLatLongInputs', true);
                }
            });

            on(dom.byId("search-option-go-button"), "click", function() {
                Finder.searchAreaByCoordinates();
            });

            on(dom.byId("clear-search-pins"), "click", function() {
                map.map.graphics.clear();
                MapModel.set('showClearPinsOption', false);
            });

            dojoQuery(".map-layer-controls li").forEach(function(node) {
                on(node, "mouseover", function(evt) {
                    self.toggleLayerList(node);
                });
            });

            on(dom.byId("master-layer-list"), "mouseleave", function() {
                domStyle.set("master-layer-list", "opacity", 0.0);
                domStyle.set("master-layer-list", "left", '-1000px');
            });

            dojoQuery(".fires_toolbox .toolbox-list li").forEach(function(node) {
                on(node, "click", MapControl.toggleFiresLayerOptions);
            });

            on(dom.byId("high-confidence"), "change", MapControl.toggleFiresConfidenceLevel);

            dojoQuery(".gfw .overlays-container .overlays-checkbox").forEach(function(node) {
                on(node, "click", MapControl.toggleOverlays);
            });

            on(dom.byId("legend-title"), "click", function() {
                MapControl.toggleLegendContainer();
            });

            on(dom.byId("reset-suitability"), "click", function() {
                MapControl.resetSuitabilitySettings();
            });

            on(dom.byId("close-suitability"), "click", function() {
                // Pass in the key from the MapConfig.LayerUI
                // for Custom Suitability Layer
                self.toggleItemInLayerList('suit');
            });

            on(dom.byId("wizard-tab"), "click", function() {
                WizardHelper.toggleWizard();
            });

            // Click info icon in suitabiliyy tools container for all sliders
            dojoQuery('.suitability-accordion .slider-name .layer-info-icon').forEach(function(node) {
                on(node, 'click', function(evt) {
                    var target = evt.target ? evt.target : evt.srcElement,
                        dataClass = target.dataset ? target.dataset.class : target.getAttribute('data-class');
                    self.showInfoPanel(dataClass);
                });
            });

            // Click info icon in suitabiliyy tools container for Headers of sections of checkboxes
            dojoQuery('.suitability-accordion .criteria-separator .layer-info-icon').forEach(function(node) {
                on(node, 'click', function(evt) {
                    var target = evt.target ? evt.target : evt.srcElement,
                        dataClass = target.dataset ? target.dataset.class : target.getAttribute('data-class');
                    self.showInfoPanel(dataClass);
                });
            });

        },

        toggleLayerList: function(el) {
            var filter = el.dataset ? el.dataset.filter : el.getAttribute('data-filter'),
                newclass = el.dataset ? el.dataset.class : el.getAttribute('data-class'),
                position = domGeom.position(el, true),
                containerWidth = 180,
                offset;

            // 200 is the default width of the container, to keep it centered, update containerWidth
            offset = (position.w - containerWidth) / 2;
            domStyle.set("master-layer-list", "left", (position.x + offset) + "px");

            // Show the Container
            Animator.fadeIn("master-layer-list", {
                duration: 100
            });
            // Add the Appropriate Class so the Items display correct color, styling etc.
            domClass.remove("master-layer-list");
            domClass.add("master-layer-list", newclass);

            // Update the list, reuse the title from the first anchor tag in the element (el)
            if (layerList) {
                layerList.setProps({
                    title: el.children[0].innerHTML,
                    filter: filter
                });
            }
        },

        renderComponents: function() {

            // Set Default Layers Here if none are present in the URL
            // Current Default Layers(lyrs) are tcc and loss
            var state = Hasher.getHash();
            // If state.lyrs is undefined, set hash, otherwise, load the layers already there
            if (state.lyrs === undefined) {
                Hasher.toggleLayers('tcc');
                Hasher.toggleLayers('loss');
            }

            MapControl.generateSuitabilitySliders();

            layerList = new LayerList({
                items: MapConfig.layersUI
            }, "master-layer-list");

            MapControl.generateTimeSliders();

        },

        toggleItemInLayerList: function(key) {
            layerList.toggleFormElement(key);
        },

        centerChange: function(x, y, zoom) {
            //debugger;
            //console.log("center change");
            //console.log(o.map);
            //compare current center and change if different
            if (!initialized) {
                return; //map not initialized yet
            }
            var currentExtent = webMercatorUtils.webMercatorToGeographic(map.map.extent);

            var extent = webMercatorUtils.webMercatorToGeographic(map.map.extent);
            var x = number.round(extent.getCenter().x, 2);
            var y = number.round(extent.getCenter().y, 2);
            var l = map.map.getLevel();

            // Hasher.setHash('x', x);
            // Hasher.setHash('y', y);
            // Hasher.setHash('l', 5);
            //var newState = HashController.newState;
            console.log(Hasher.getHash());
            var state = Hasher.getHash();

            // Hasher.toggleLayers('tcc');
            // Hasher.toggleLayers('loss');

            var centerChangeByUrl = ((parseFloat(state.x) != x) || (parseFloat(state.y) != y) || (parseInt(state.l) != l));
            console.log(centerChangeByUrl + " " + state.y + " " + state.x);
            if (centerChangeByUrl) {
                //o.mapExtentPausable.pause();
                // on.once(map.map, "extent-change", function() {
                //     o.mapExtentPausable.resume();
                // });
                var ptWM = webMercatorUtils.geographicToWebMercator(new Point(parseFloat(state.x), parseFloat(state.y)));

                map.map.centerAndZoom(ptWM, parseInt(state.l));

                // Hasher.setHash(x, xValue);
                // Hasher.setHash(y, yValue);
            }
        },

        showInfoPanel: function(infoPanelClass) {
            if (typeof(infoPanelClass) === 'object') {
                var content = infoPanelClass;
                MapControl.createDialogBox(content);
            } else {
                if (dataDivLoaded) {
                    var content = infoDiv.querySelector("." + infoPanelClass);
                    MapControl.createDialogBox(content);
                } else {
                    Loader.getTemplate("data").then(function(template) {
                        dataDivLoaded = true;
                        infoDiv.innerHTML = template;
                        var content = infoDiv.querySelector("." + infoPanelClass);
                        MapControl.createDialogBox(content);
                    })
                }
            }
        }
    };

});<|endoftext|>


<commit_before>/**
 * The DatePicker Component
 *
 * @module aui-datepicker
 */

var Lang = A.Lang,

    clamp = function(value, min, max) {
        return Math.min(Math.max(value, min), max);
    };

/**
 * A base class for `DatePickerBase`.
 *
 * @class A.DatePickerBase
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 */

function DatePickerBase() {}

/**
 * Lists `CalendarBase` pane templates.
 *
 * @property PANES
 * @type {Array}
 * @static
 */
DatePickerBase.PANES = [
    A.CalendarBase.ONE_PANE_TEMPLATE,
    A.CalendarBase.TWO_PANE_TEMPLATE,
    A.CalendarBase.THREE_PANE_TEMPLATE
];

/**
 * Static property used to define the default attribute configuration for the
 * `DatePickerBase`.
 *
 * @property ATTRS
 * @type {Object}
 * @static
 */
DatePickerBase.ATTRS = {

    /**
     * Sets the initial visibility.
     *
     * @attribute autoHide
     * @default true
     * @type {Boolean}
     */
    autoHide: {
        validator: Lang.isBoolean,
        value: true
    },

    /**
     * Stores the configuration of the `Calendar` instance.
     *
     * @attribute calendar
     * @default {}
     * @writeOnce
     */
    calendar: {
        setter: '_setCalendar',
        value: {},
        writeOnce: true
    },

    /**
     * Defines how many panes should be rendered.
     *
     * @attribute panes
     * @default 1
     * @type {Number}
     * @writeOnce
     */
    panes: {
        setter: '_setPanes',
        validator: Lang.isNumber,
        value: 1,
        writeOnce: true
    }
};

A.mix(DatePickerBase.prototype, {
    calendar: null,

    /**
     * Construction logic executed during `DatePickerBase` instantiation.
     * Lifecycle.
     *
     * @method initializer
     * @protected
     */
    initializer: function() {
        var instance = this;

        instance.after('selectionChange', instance._afterDatePickerSelectionChange);
    },

    /**
     * Clears a selection in the `Calendar`.
     *
     * @method clearSelection
     * @param silent
     */
    clearSelection: function(silent) {
        var instance = this;

        instance.getCalendar()._clearSelection(silent);
    },

    /**
     * Deselects a date in the `Calendar`.
     *
     * @method deselectDates
     * @param dates
     */
    deselectDates: function(dates) {
        var instance = this;

        instance.getCalendar().deselectDates(dates);
    },

    /**
     * Returns an existent `Calendar` instance or creates a new one if it
     * doesn't exists.
     *
     * @method getCalendar
     * @return {Calendar}
     */
    getCalendar: function() {
        var instance = this,
            calendar = instance.calendar,
            originalCalendarTemplate;

        if (!calendar) {
            // CalendarBase leaks a functionality to dinamically switch the
            // template. Therefore, switch it to respect panels configuration
            // attribute, then switch it back after calendar renders.
            originalCalendarTemplate = A.CalendarBase.CONTENT_TEMPLATE;
            A.CalendarBase.CONTENT_TEMPLATE =
                DatePickerBase.PANES[instance.get('panes') - 1];

            // Initialize the popover instance before calendar renders since it
            // will use popover.bodyNode as render node.
            instance.getPopover();

            calendar = new A.Calendar(instance.get('calendar'));
            calendar.render(instance.popover.bodyNode);
            instance.calendar = calendar;

            calendar.after(
                'selectionChange', instance._afterCalendarSelectionChange,
                instance);
            calendar.after(
                'dateClick', instance._afterCalendarDateClick,
                instance);

            // Restore the original CalendarBase template.
            A.CalendarBase.CONTENT_TEMPLATE = originalCalendarTemplate;
        }

        return calendar;
    },

    /**
     * Selects a date in the `Calendar`.
     *
     * @method selectDates
     * @param dates
     */
    selectDates: function(dates) {
        var instance = this;

        instance.getCalendar().selectDates(dates);
    },

    /**
     * Selects dates in the 'Calendar' while only allowing
     * the calendar to fire 'selectionChange' once.
     *
     * @method selectDatesFromInputValue
     * @param dates
     */
    selectDatesFromInputValue: function(dates) {
        var instance = this,
            calendar = instance.getCalendar();

        A.Array.each(
            dates,
            function(date) {
                calendar._addDateToSelection(date, true);
            }
        );

        calendar._fireSelectionChange();
    },

    /**
     * Renders the widget in an `<input>` node.
     *
     * @method useInputNode
     * @param node
     */
    useInputNode: function(node) {
        var instance = this,
            popover = instance.getPopover();

        popover.set('trigger', node);
        instance.set('activeInput', node);

        if (!popover.get('visible')) {
            instance.alignTo(node);
        }

        if (node) {
            node.detach('keydown', instance._handleKeydownEvent);

            node.on('keydown', instance._handleKeydownEvent, instance);
        }

        instance.clearSelection(true);
        instance.selectDatesFromInputValue(instance.getParsedDatesFromInputValue());
    },

    /**
     * Fires after a click in the `Calendar` date.
     *
     * @method _afterCalendarDateClick
     * @protected
     */
    _afterCalendarDateClick: function() {
        var instance = this,
            calendar = instance.getCalendar(),
            selectionMode = calendar.get('selectionMode');

        if (instance.get('autoHide') && (selectionMode !== 'multiple')) {
            instance.hide();
        }
    },

    /**
     * Fires after a selection change in the `Calendar`.
     *
     * @method _afterCalendarSelectionChange
     * @param event
     * @protected
     */
    _afterCalendarSelectionChange: function(event) {
        var instance = this,
            newDates,
            newSelection = event.newSelection,
            prevDates = instance.getSelectedDates() || [];

        newDates = newSelection.concat(prevDates);

        newDates = A.Array.dedupe(newDates);

        if (newDates.length !== prevDates.length || newSelection.length < prevDates.length) {
            instance.fire('selectionChange', {
                newSelection: newSelection
            });
        }
    },

    /**
     * Fires when a selection change in the `DatePicker`.
     *
     * @method _afterDatePickerSelectionChange
     * @protected
     */
    _afterDatePickerSelectionChange: function() {
        var instance = this;

        instance._setCalendarToFirstSelectedDate();
    },

    /**
    * Handles keydown events
    *
    * @method _handleKeydownEvent
    * @param event
    * @protected
    */
    _handleKeydownEvent: function(event) {
        var instance = this;

        if (event.isKey('enter')) {
            instance.fire('enterKey');
        }
    },

    /**
     * Checks if the given dates are referencing the same
     * day, month and year.
     *
     * @method _isSameDay
     * @param date1
     * @param date2
     * @protected
     */
    _isSameDay: function(date1, date2) {
        return date1.getDate() === date2.getDate() &&
            date1.getMonth() === date2.getMonth() &&
            date1.getFullYear() === date2.getFullYear();
    },

    /**
     * Fires when the user's first interaction happens.
     *
     * @method _onceUserInteractionRelease
     * @param event
     * @protected
     */
    _onceUserInteractionRelease: function(event) {
        var instance = this;

        instance.useInputNodeOnce(event.currentTarget);

        instance.alignTo(event.currentTarget);

        instance._userInteractionInProgress = false;
    },

    /**
     * Sets the first selected date in the `Calendar`.
     *
     * @method _setCalendarToFirstSelectedDate
     * @protected
     */
    _setCalendarToFirstSelectedDate: function() {
        var instance = this,
            dates = instance.getSelectedDates(),
            firstSelectedDate = dates[0];

        if (firstSelectedDate) {
            instance.getCalendar().set('date', firstSelectedDate);
        }
    },

    /**
     * Sets the `calendar` value by merging its object with another properties.
     *
     * @method _setCalendar
     * @param val
     * @protected
     */
    _setCalendar: function(val) {
        return A.merge({
            showNextMonth: true,
            showPrevMonth: true
        }, val);
    },

    /**
     * Sets the `pane` value between 1 and 3.
     *
     * @method _setPanes
     * @param val
     * @protected
     * @return {Number} Clamped number of panes.
     */
    _setPanes: function(val) {
        return clamp(val, 1, 3);
    }
}, true);

A.DatePickerBase = DatePickerBase;

/**
 * A base class for `DatePicker`.
 *
 * @class A.DatePicker
 * @extends Base
 * @uses A.DatePickerDelegate, A.DatePickerPopover, A.DatePickerBase
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 * @include http://alloyui.com/examples/datepicker/basic-markup.html
 * @include http://alloyui.com/examples/datepicker/basic.js
 */
A.DatePicker = A.Base.create('datepicker', A.Base, [A.DatePickerDelegate, A.DatePickerPopover, A.DatePickerBase]);
<commit_msg>AUI-1783 Detach listener from old node first<commit_after>/**
 * The DatePicker Component
 *
 * @module aui-datepicker
 */

var Lang = A.Lang,

    clamp = function(value, min, max) {
        return Math.min(Math.max(value, min), max);
    };

/**
 * A base class for `DatePickerBase`.
 *
 * @class A.DatePickerBase
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 */

function DatePickerBase() {}

/**
 * Lists `CalendarBase` pane templates.
 *
 * @property PANES
 * @type {Array}
 * @static
 */
DatePickerBase.PANES = [
    A.CalendarBase.ONE_PANE_TEMPLATE,
    A.CalendarBase.TWO_PANE_TEMPLATE,
    A.CalendarBase.THREE_PANE_TEMPLATE
];

/**
 * Static property used to define the default attribute configuration for the
 * `DatePickerBase`.
 *
 * @property ATTRS
 * @type {Object}
 * @static
 */
DatePickerBase.ATTRS = {

    /**
     * Sets the initial visibility.
     *
     * @attribute autoHide
     * @default true
     * @type {Boolean}
     */
    autoHide: {
        validator: Lang.isBoolean,
        value: true
    },

    /**
     * Stores the configuration of the `Calendar` instance.
     *
     * @attribute calendar
     * @default {}
     * @writeOnce
     */
    calendar: {
        setter: '_setCalendar',
        value: {},
        writeOnce: true
    },

    /**
     * Defines how many panes should be rendered.
     *
     * @attribute panes
     * @default 1
     * @type {Number}
     * @writeOnce
     */
    panes: {
        setter: '_setPanes',
        validator: Lang.isNumber,
        value: 1,
        writeOnce: true
    }
};

A.mix(DatePickerBase.prototype, {
    calendar: null,

    /**
     * Construction logic executed during `DatePickerBase` instantiation.
     * Lifecycle.
     *
     * @method initializer
     * @protected
     */
    initializer: function() {
        var instance = this;

        instance.after('selectionChange', instance._afterDatePickerSelectionChange);
    },

    /**
     * Clears a selection in the `Calendar`.
     *
     * @method clearSelection
     * @param silent
     */
    clearSelection: function(silent) {
        var instance = this;

        instance.getCalendar()._clearSelection(silent);
    },

    /**
     * Deselects a date in the `Calendar`.
     *
     * @method deselectDates
     * @param dates
     */
    deselectDates: function(dates) {
        var instance = this;

        instance.getCalendar().deselectDates(dates);
    },

    /**
     * Returns an existent `Calendar` instance or creates a new one if it
     * doesn't exists.
     *
     * @method getCalendar
     * @return {Calendar}
     */
    getCalendar: function() {
        var instance = this,
            calendar = instance.calendar,
            originalCalendarTemplate;

        if (!calendar) {
            // CalendarBase leaks a functionality to dinamically switch the
            // template. Therefore, switch it to respect panels configuration
            // attribute, then switch it back after calendar renders.
            originalCalendarTemplate = A.CalendarBase.CONTENT_TEMPLATE;
            A.CalendarBase.CONTENT_TEMPLATE =
                DatePickerBase.PANES[instance.get('panes') - 1];

            // Initialize the popover instance before calendar renders since it
            // will use popover.bodyNode as render node.
            instance.getPopover();

            calendar = new A.Calendar(instance.get('calendar'));
            calendar.render(instance.popover.bodyNode);
            instance.calendar = calendar;

            calendar.after(
                'selectionChange', instance._afterCalendarSelectionChange,
                instance);
            calendar.after(
                'dateClick', instance._afterCalendarDateClick,
                instance);

            // Restore the original CalendarBase template.
            A.CalendarBase.CONTENT_TEMPLATE = originalCalendarTemplate;
        }

        return calendar;
    },

    /**
     * Selects a date in the `Calendar`.
     *
     * @method selectDates
     * @param dates
     */
    selectDates: function(dates) {
        var instance = this;

        instance.getCalendar().selectDates(dates);
    },

    /**
     * Selects dates in the 'Calendar' while only allowing
     * the calendar to fire 'selectionChange' once.
     *
     * @method selectDatesFromInputValue
     * @param dates
     */
    selectDatesFromInputValue: function(dates) {
        var instance = this,
            calendar = instance.getCalendar();

        A.Array.each(
            dates,
            function(date) {
                calendar._addDateToSelection(date, true);
            }
        );

        calendar._fireSelectionChange();
    },

    /**
     * Renders the widget in an `<input>` node.
     *
     * @method useInputNode
     * @param node
     */
    useInputNode: function(node) {
        var instance = this,
            popover = instance.getPopover();

        if (instance.get('activeInput')) {
            instance.get('activeInput').detach('keydown', instance._handleKeydownEvent, instance);
        }

        popover.set('trigger', node);
        instance.set('activeInput', node);

        if (!popover.get('visible')) {
            instance.alignTo(node);
        }

        if (node) {
            node.on('keydown', instance._handleKeydownEvent, instance);
        }

        instance.clearSelection(true);
        instance.selectDatesFromInputValue(instance.getParsedDatesFromInputValue());
    },

    /**
     * Fires after a click in the `Calendar` date.
     *
     * @method _afterCalendarDateClick
     * @protected
     */
    _afterCalendarDateClick: function() {
        var instance = this,
            calendar = instance.getCalendar(),
            selectionMode = calendar.get('selectionMode');

        if (instance.get('autoHide') && (selectionMode !== 'multiple')) {
            instance.hide();
        }
    },

    /**
     * Fires after a selection change in the `Calendar`.
     *
     * @method _afterCalendarSelectionChange
     * @param event
     * @protected
     */
    _afterCalendarSelectionChange: function(event) {
        var instance = this,
            newDates,
            newSelection = event.newSelection,
            prevDates = instance.getSelectedDates() || [];

        newDates = newSelection.concat(prevDates);

        newDates = A.Array.dedupe(newDates);

        if (newDates.length !== prevDates.length || newSelection.length < prevDates.length) {
            instance.fire('selectionChange', {
                newSelection: newSelection
            });
        }
    },

    /**
     * Fires when a selection change in the `DatePicker`.
     *
     * @method _afterDatePickerSelectionChange
     * @protected
     */
    _afterDatePickerSelectionChange: function() {
        var instance = this;

        instance._setCalendarToFirstSelectedDate();
    },

    /**
    * Handles keydown events
    *
    * @method _handleKeydownEvent
    * @param event
    * @protected
    */
    _handleKeydownEvent: function(event) {
        var instance = this;

        if (event.isKey('enter')) {
            instance.fire('enterKey');
        }
    },

    /**
     * Checks if the given dates are referencing the same
     * day, month and year.
     *
     * @method _isSameDay
     * @param date1
     * @param date2
     * @protected
     */
    _isSameDay: function(date1, date2) {
        return date1.getDate() === date2.getDate() &&
            date1.getMonth() === date2.getMonth() &&
            date1.getFullYear() === date2.getFullYear();
    },

    /**
     * Fires when the user's first interaction happens.
     *
     * @method _onceUserInteractionRelease
     * @param event
     * @protected
     */
    _onceUserInteractionRelease: function(event) {
        var instance = this;

        instance.useInputNodeOnce(event.currentTarget);

        instance.alignTo(event.currentTarget);

        instance._userInteractionInProgress = false;
    },

    /**
     * Sets the first selected date in the `Calendar`.
     *
     * @method _setCalendarToFirstSelectedDate
     * @protected
     */
    _setCalendarToFirstSelectedDate: function() {
        var instance = this,
            dates = instance.getSelectedDates(),
            firstSelectedDate = dates[0];

        if (firstSelectedDate) {
            instance.getCalendar().set('date', firstSelectedDate);
        }
    },

    /**
     * Sets the `calendar` value by merging its object with another properties.
     *
     * @method _setCalendar
     * @param val
     * @protected
     */
    _setCalendar: function(val) {
        return A.merge({
            showNextMonth: true,
            showPrevMonth: true
        }, val);
    },

    /**
     * Sets the `pane` value between 1 and 3.
     *
     * @method _setPanes
     * @param val
     * @protected
     * @return {Number} Clamped number of panes.
     */
    _setPanes: function(val) {
        return clamp(val, 1, 3);
    }
}, true);

A.DatePickerBase = DatePickerBase;

/**
 * A base class for `DatePicker`.
 *
 * @class A.DatePicker
 * @extends Base
 * @uses A.DatePickerDelegate, A.DatePickerPopover, A.DatePickerBase
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 * @include http://alloyui.com/examples/datepicker/basic-markup.html
 * @include http://alloyui.com/examples/datepicker/basic.js
 */
A.DatePicker = A.Base.create('datepicker', A.Base, [A.DatePickerDelegate, A.DatePickerPopover, A.DatePickerBase]);
<|endoftext|>