climate-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jo...@apache.org
Subject svn commit: r1562255 [3/19] - in /incubator/climate/trunk/ocw-ui: ./ frontend/ frontend/app/ frontend/app/css/ frontend/app/css/lib/ frontend/app/font/ frontend/app/img/ frontend/app/js/ frontend/app/js/controllers/ frontend/app/js/directives/ frontend...
Date Tue, 28 Jan 2014 22:18:20 GMT
Propchange: incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.svg
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.ttf
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.ttf?rev=1562255&view=auto
==============================================================================
Files incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.ttf (added) and incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.ttf Tue Jan 28 22:18:16 2014 differ

Propchange: incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.ttf
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.woff
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.woff?rev=1562255&view=auto
==============================================================================
Files incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.woff (added) and incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.woff Tue Jan 28 22:18:16 2014 differ

Propchange: incubator/climate/trunk/ocw-ui/frontend/app/font/fontawesome-webfont.woff
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/climate/trunk/ocw-ui/frontend/app/img/globe.png
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/img/globe.png?rev=1562255&view=auto
==============================================================================
Files incubator/climate/trunk/ocw-ui/frontend/app/img/globe.png (added) and incubator/climate/trunk/ocw-ui/frontend/app/img/globe.png Tue Jan 28 22:18:16 2014 differ

Added: incubator/climate/trunk/ocw-ui/frontend/app/img/glyphicons-halflings-white.png
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/img/glyphicons-halflings-white.png?rev=1562255&view=auto
==============================================================================
Files incubator/climate/trunk/ocw-ui/frontend/app/img/glyphicons-halflings-white.png (added) and incubator/climate/trunk/ocw-ui/frontend/app/img/glyphicons-halflings-white.png Tue Jan 28 22:18:16 2014 differ

Added: incubator/climate/trunk/ocw-ui/frontend/app/img/glyphicons-halflings.png
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/img/glyphicons-halflings.png?rev=1562255&view=auto
==============================================================================
Files incubator/climate/trunk/ocw-ui/frontend/app/img/glyphicons-halflings.png (added) and incubator/climate/trunk/ocw-ui/frontend/app/img/glyphicons-halflings.png Tue Jan 28 22:18:16 2014 differ

Added: incubator/climate/trunk/ocw-ui/frontend/app/index.html
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/index.html?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/index.html (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/index.html Tue Jan 28 22:18:16 2014
@@ -0,0 +1,125 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~    http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<!doctype html>
+<html lang="en" ng-app="ocw">
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>OCW UI</title>
+  <link rel="stylesheet" href="css/lib/bootstrap.min.css"/>
+  <link rel="stylesheet" href="css/lib/bootstrap-responsive.min.css"/>
+  <link rel="stylesheet" href="css/lib/font-awesome.min.css"/>
+  <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.css" />
+  <link rel="stylesheet" href="css/lib/timeline.css"/>
+  <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/ui-lightness/jquery-ui.min.css" type="text/css"/> 
+  <!--[if lte IE 8]>
+    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.ie.css" />
+  <![endif]-->
+  <link rel="stylesheet" href="css/app.css"/>
+</head>
+<body ng-cloak>
+
+<div class="container">
+  <div class="row-fluid">
+    <div class="span12">
+      <!-- Title -->
+      <div class="row-fluid">
+        <div class="span12">
+        <br><br>
+        <div id="header">
+          <img id="header-img" src=""/>
+          <h3 id="header-title">Project Name</h3>
+          <h5 id="OCW-powered">Powered by Apache Open Climate Workbench</h5>
+        </div>
+        </div>
+      </div>
+      <!-- Navigation bar -->
+      <div class="row-fluid">
+      <div class="navbar navbar-fixed-top">
+       <div class="navbar-inner">
+         <div class="container">
+           <a class="brand" href="#">OCW UI</a>
+           <ul class="nav">
+             <li ng-class="{ active: $state.includes('main') }"><a href="#">Evaluate</a></li>
+             <li ng-class="{ active: $state.includes('results') }"><a href="#/results">Results</a></li>
+           </ul>
+         </div>
+       </div>
+      </div>
+      </div>
+    </div>
+  </div>
+  <!-- Main Content -->
+  <div id="main-container" class="container" ui-view ng-animate="{enter:'fade-enter'}"></div>
+</div>
+
+  <!--Libraries-->
+  <script src="js/lib/jquery/jquery-1.10.1.js"></script>
+  <script src="js/lib/jquery/jquery-ui/jquery-ui-1.10.3.min.js"></script>
+  <script src="js/lib/angular/angular.min.js"></script>
+  <script src="js/lib/angular-ui/angular-ui-0.4-tpls.js"></script>
+  <script src="js/lib/jquery/jquery-ui/datepicker-wrapper/date.js"></script>
+  <script src="js/lib/bootstrap/bootstrap.js"></script>
+  <script src="js/lib/leaflet/leaflet-0.5.js"></script>
+  <script src="http://www.google.com/jsapi"></script>
+  <script src="js/lib/timeline/timeline.js"></script>
+  <script src="js/lib/angular-ui/angular-ui-router.min.js"></script>
+  <script src="js/lib/angular-ui/ui-bootstrap-tpls-0.5.0.min.js"></script>
+  <!--Timeline refuses to initialize nicely so we're doing this as a workaround-->
+  <script type="text/javascript">google.load("visualization", "1");</script>
+  
+  <!--General-->
+  <script src="js/app.js"></script>
+
+  <!--Services-->
+  <script src="js/services/SelectedDatasetInformation.js"></script>
+  <script src="js/services/RegionSelectParams.js"></script>
+  <script src="js/services/EvaluationSettings.js"></script>
+
+  <!--Controllers-->
+  <script src="js/controllers/WorldMapCtrl.js"></script>
+  <script src="js/controllers/ParameterSelectCtrl.js"></script>
+  <script src="js/controllers/DatasetDisplayCtrl.js"></script>
+  <script src="js/controllers/ObservationSelectCtrl.js"></script>
+  <script src="js/controllers/RcmedSelectionCtrl.js"></script>
+  <script src="js/controllers/SettingsCtrl.js"></script>
+  <script src="js/controllers/TimelineCtrl.js"></script>
+  <script src="js/controllers/DatasetSelectCtrl.js"></script>
+  <script src="js/controllers/ResultCtrl.js"></script>
+  <script src="js/controllers/ResultDetailCtrl.js"></script>
+
+  <!--Directives-->
+  <script src="js/directives/LeafletMap.js"></script>
+  <script src="js/directives/PreviewMap.js"></script>
+  <script src="js/directives/BootstrapModal.js"></script>
+  <script src="js/directives/BootstrapModalOpen.js"></script>
+  <script src="js/directives/PredictiveFileBrowserInput.js"></script>
+  <script src="js/directives/OnBlur.js"></script>
+  <script src="js/directives/Timeline.js"></script>
+
+  <!--Filters-->
+  <script src="js/filters/ISODateToMiddleEndian.js"></script>
+</body>
+<footer class="container well well-small" style="margin-top: 40px">
+  <div class="span4 offset1">
+    <h6>Powered by Apache Open Climate Workbench</h6>
+  </div>
+</footer>
+</html>

Propchange: incubator/climate/trunk/ocw-ui/frontend/app/index.html
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/app.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/app.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/app.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/app.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+'use strict';
+
+// We're creating a "global" application object. This allows us to keep module 
+// names isolated to a single location as well as simplifying future init code.
+var App =  App || {};
+
+App.Services = angular.module('ocw.services', []);
+App.Directives = angular.module('ocw.directives', []);
+App.Controllers = angular.module('ocw.controllers', []);
+App.Filters = angular.module('ocw.filters', []);
+
+angular.module('ocw', ['ocw.services', 'ocw.directives', 'ocw.controllers', 'ocw.filters', 'ui.date', 'ui.bootstrap', 'ui.compat', 'ui.state'])
+.config(
+    [        '$stateProvider', '$routeProvider', '$urlRouterProvider',
+    function ($stateProvider,   $routeProvider,   $urlRouterProvider) {
+      $urlRouterProvider
+        .when('/r?id', '/results/:id')
+        .otherwise('/');
+
+      $routeProvider
+        .when('/evaluation/:id', {
+          redirectTo: '/results/:id',
+        })
+        .when('/', {
+          redirectTo: '/evaluate',
+        });
+
+      $stateProvider
+        .state('main',{
+          url: '/evaluate',
+          templateUrl: 'partials/main.html',
+        })
+        .state('results', {
+          url: '/results',
+          abstract: true,
+          templateUrl: 'partials/results.html',
+          controller: 'ResultCtrl'
+        })
+        .state('results.list', {
+          // parent: 'results',
+          url: '',
+          templateUrl: 'partials/results.list.html',
+        })
+        .state('results.detail', {
+          // parent: 'results',
+          url: '/{resultId}',
+          views: {
+            '': {
+              templateUrl: 'partials/results.detail.html',
+              controller: 'ResultDetailCtrl'
+            },
+            'menu': {
+              templateProvider:
+                [ '$stateParams',
+                function ($stateParams){
+                  return '<hr><small class="muted">result ID: ' + $stateParams.resultId + '</small>';
+                }],
+            },
+          },
+        });
+    }])
+.run(
+    [        '$rootScope', '$state', '$stateParams',
+    function ($rootScope,   $state,   $stateParams) {
+      $rootScope.$state = $state;
+      $rootScope.$stateParams = $stateParams;
+      $rootScope.evalResults = ""; 
+      $rootScope.fillColors = ['#ff0000', '#00c90d', '#cd0074', '#f3fd00'];
+      $rootScope.surroundColors = ['#a60000', '#008209', '#8f004b', '#93a400']
+      $rootScope.baseURL = 'http://localhost:8082';
+}]);
+

Propchange: incubator/climate/trunk/ocw-ui/frontend/app/js/app.js
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/DatasetDisplayCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/DatasetDisplayCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/DatasetDisplayCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/DatasetDisplayCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Controller for dataset display
+App.Controllers.controller('DatasetDisplayCtrl', ['$rootScope', '$scope', 'selectedDatasetInformation', 
+function($rootScope, $scope, selectedDatasetInformation) {
+	$scope.datasets = selectedDatasetInformation.getDatasets();
+
+	$scope.removeDataset = function($index) {
+		selectedDatasetInformation.removeDataset($index);
+	}
+
+	$scope.setRegridBase = function(index) {
+		for (var i = 0; i < $scope.datasets.length; i++) {
+			$scope.datasets[i].regrid = ((i == index) ? $scope.datasets[i].regrid : false);
+		}
+	}
+}]);

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/DatasetSelectCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/DatasetSelectCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/DatasetSelectCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/DatasetSelectCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Controller for dataset selection/modification
+App.Controllers.controller('DatasetSelectCtrl', ['$scope', 'selectedDatasetInformation',
+function($scope, selectedDatasetInformation) {
+
+    // Grab a copy of the datasets so we can display a count to the user!
+    $scope.datasetCount = selectedDatasetInformation.getDatasets();
+
+    $scope.shouldDisableClearButton = function() {
+      return (selectedDatasetInformation.getDatasetCount() == 0);
+    }
+
+    $scope.clearDatasets = function() {
+      selectedDatasetInformation.clearDatasets();
+    }
+
+    $scope.open = function () {
+      $scope.datasetSelect = true;
+    }
+
+    $scope.close = function () {
+      $scope.datasetSelect = false;
+    }
+
+    $scope.opts = {
+      backdropFade: true,
+      dialogFade:true
+    };
+
+    $scope.templates =
+      [ { title:'Local File', url: 'partials/selectObservation.html'}
+      , { title:'RCMED', url: 'partials/selectRcmed.html'}
+      , { title:'ESG', disabled: true } ];
+
+    $scope.template = $scope.templates[0];
+
+}]);

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ObservationSelectCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ObservationSelectCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ObservationSelectCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ObservationSelectCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Controller for observation selection in modal
+App.Controllers.controller('ObservationSelectCtrl', ['$rootScope', '$scope', '$http', '$q', '$timeout', 'selectedDatasetInformation',
+function($rootScope, $scope, $http, $q, $timeout, selectedDatasetInformation) {
+	// Grab a copy of the datasets so we can display a count to the user!
+	$scope.datasetCount = selectedDatasetInformation.getDatasets();
+
+	// Initalize the option arrays and default to the first element
+	$scope.params      = ["Please select a file above"];
+	$scope.paramSelect = $scope.params[0];
+	$scope.lats        = ["Please select a file above"];
+	$scope.latsSelect  = $scope.lats[0];
+	$scope.lons        = ["Please select a file above"];
+	$scope.lonsSelect  = $scope.lons[0];
+	$scope.times       = ["Please select a file above"];
+	$scope.timeSelect  = $scope.times[0];
+
+	// Grab the path leader information that the webserver is using to limit directory access.
+	$scope.pathLeader = 'False';
+	$http.jsonp($rootScope.baseURL + '/getPathLeader/?callback=JSON_CALLBACK').
+		success(function(data) {
+			$scope.pathLeader = data.leader;
+	});
+
+	// Toggle load button view depending on upload state of selected files
+	$scope.loadingFile = false;
+
+	// Toggle display of a confirmation when loading a dataset
+	$scope.fileAdded = false;
+
+	$scope.latLonVals = [];
+	$scope.timeVals = [];
+	$scope.localSelectForm = {};
+
+	$scope.uploadLocalFile = function() {
+		$scope.loadingFile = true;
+
+		// TODO: Need to try to validate the input a bit. At least make sure we're not
+		// pointing at a directory perhaps?
+		
+		// TODO: Two-way binding with ng-model isn't being used here because it fails to update
+		// properly with the auto-complete that we're using on the input box. So we're doing
+		// it the wrong way temporarily...
+		var input = $('#observationFileInput').val();
+
+		// If the backend is limiting directory access we need to add that leader to our path
+		// so it remains valid!
+		if ($scope.pathLeader != 'False') {
+			input = $scope.pathLeader + input
+		}
+
+		// TODO: We're not really handling the case where there is a failure here at all. 
+		// Should check for fails and allow the user to make changes.
+		//
+		// Get model variables
+		var varsPromise = $http.jsonp($rootScope.baseURL + '/list/vars/"' + input + '"?callback=JSON_CALLBACK');
+		// Get Lat and Lon variables
+		var latlonPromise = $http.jsonp($rootScope.baseURL + '/list/latlon/"' + input + '"?callback=JSON_CALLBACK');
+		// Get Time variables
+		var timesPromise = $http.jsonp($rootScope.baseURL + '/list/time/"' + input + '"?callback=JSON_CALLBACK');
+
+		$q.all([varsPromise, latlonPromise, timesPromise]).then(
+			// Handle success fetches!
+			function(arrayOfResults) {
+				$scope.loadingFile = false;
+
+				// Handle lat/lon results
+				var data = arrayOfResults[1].data;
+				$scope.lats = [data.latname];
+				$scope.lons = [data.lonname];
+				$scope.latLonVals = [data.latMin, data.latMax, data.lonMin, data.lonMax];
+
+				// If there is more than one option for the user, tell them they need to pick one!
+				if ($scope.lats.length > 1) $scope.lats.splice(0, 0, "Please select an option");
+				if ($scope.lons.length > 1) $scope.lons.splice(0, 0, "Please select an option");
+				// Default the display to the first available option.
+				$scope.latsSelect = $scope.lats[0];
+				$scope.lonsSelect = $scope.lons[0];
+
+				// Handle time results
+				var data = arrayOfResults[2].data
+				$scope.times = [data.timename];
+				$scope.timeVals = [data.start_time, data.end_time];
+
+				if ($scope.times.length > 1) $scope.times.splice(0, 0, "Please select an option");
+				$scope.timeSelect = $scope.times[0];
+
+				// Handle parameter results
+				var data = arrayOfResults[0].data.variables;
+				$scope.params = (data instanceof Array) ? data : [data];
+				$scope.params = $.grep($scope.params, 
+									function(val) {
+										return ($.inArray(val, $scope.lats)  != 0 && 
+												$.inArray(val, $scope.lons)  != 0 && 
+												$.inArray(val, $scope.times) != 0);
+									});
+				
+				if ($scope.params.length > 1) $scope.params.splice(0, 0, "Please select an option");
+				$scope.paramSelect = $scope.params[0];
+			},
+			// Uh oh! AT LEAST on of our fetches failed
+			function(arrayOfFailure) {
+				$scope.loadingFile = false;
+
+				$scope.params      = ["Unable to load variable(s)"];
+				$scope.paramSelect = $scope.params[0];
+				$scope.lats        = ["Unable to load variable(s)"];
+				$scope.latsSelect  = $scope.lats[0];
+				$scope.lons        = ["Unable to load variable(s)"];
+				$scope.lonsSelect  = $scope.lons[0];
+				$scope.times       = ["Unable to load variable(s)"];
+				$scope.timeSelect  = $scope.times[0];
+			}
+		);
+	};
+
+	$scope.addDataSet = function() {
+		// TODO: Need to verify that all the variables selected are correct!!!
+		// TODO: We shouldn't allow different parameters to match the same variables!!
+
+		var newDataset = {};
+		var input = $('#observationFileInput').val();
+
+		// If the backend is limiting directory access we need to add that leader to our path
+		// so it remains valid!
+		if ($scope.pathLeader != 'False') {
+			input = $scope.pathLeader + input
+		}
+
+		newDataset['isObs'] = 0;
+		// Save the model path. Note that the path is effectively the "id" for the model.
+		newDataset['id'] = input;
+		// Grab the file name later for display purposes.
+		var splitFilePath = input.split('/');
+		newDataset['name'] = splitFilePath[splitFilePath.length - 1];
+		// Save the model parameter variable. We save it twice for consistency and display convenience.
+		newDataset['param'] = $scope.paramSelect;
+		newDataset['paramName'] = newDataset['param'];
+		// Save the lat/lon information
+		newDataset['lat'] = $scope.latsSelect;
+		newDataset['lon'] = $scope.lonsSelect;
+
+		newDataset['latlonVals'] = {"latMin": $scope.latLonVals[0], "latMax": $scope.latLonVals[1],
+									"lonMin": $scope.latLonVals[2], "lonMax": $scope.latLonVals[3]};
+		// Get the time information
+		newDataset['time'] = $scope.timeSelect;
+		newDataset['timeVals'] = {"start": $scope.timeVals[0], "end": $scope.timeVals[1]};
+
+		selectedDatasetInformation.addDataset(newDataset);
+
+		// Reset all the fields!!
+		$scope.params = ["Please select a file above"];
+		$scope.paramSelect = $scope.params[0];
+		$scope.lats = ["Please select a file above"];
+		$scope.latsSelect = $scope.lats[0];
+		$scope.lons = ["Please select a file above"];
+		$scope.lonsSelect = $scope.lons[0];
+		$scope.times = ["Please select a file above"];
+		$scope.timeSelect = $scope.times[0];
+		$scope.latLonVals = [];
+		$scope.timeVals = [];
+
+		// Clear the input box
+		$('#observationFileInput').val("");
+
+		// Display a confirmation message for a little bit
+		$scope.fileAdded = true;
+		$timeout(function() {
+			$scope.fileAdded = false;
+		}, 2000);
+	}
+
+	$scope.shouldDisableLoadButton = function() {
+		return $scope.loadingFile;
+	}
+}]);

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ParameterSelectCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ParameterSelectCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ParameterSelectCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ParameterSelectCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Controller for dataset parameter selection/modification
+App.Controllers.controller('ParameterSelectCtrl', ['$rootScope', '$scope', '$http', '$timeout', 
+						   'selectedDatasetInformation', 'regionSelectParams', 'evaluationSettings', 
+function($rootScope, $scope, $http, $timeout, selectedDatasetInformation, regionSelectParams, evaluationSettings) {
+	$scope.datasets = selectedDatasetInformation.getDatasets();
+
+	// The min/max lat/lon values from the selected datasets
+	$scope.latMin = -90;
+	$scope.latMax = 90;
+	$scope.lonMin = -180;
+	$scope.lonMax = 180;
+	$scope.start = "1980-01-01 00:00:00";
+	$scope.end = "2030-01-01 00:00:00";
+
+	// The min/max lat/lon values that are displayed
+	$scope.displayParams = regionSelectParams.getParameters();
+
+	$scope.runningEval = false;
+
+	// Flag for toggling re-grid controls based on whether or not the user has selected a grid
+	// base from the selected datasets. By default we have no datasets so we don't need to show
+	// the controls!
+	$scope.areInUserRegridState = false;
+
+	// Initialization for the lat/lon grid step sliders
+	// TODO There has to be a better way of dealing with this. Perhaps a directive??
+	$scope.latSliderVal = 0;
+	$scope.lonSliderVal = 0;
+
+	$('#latSlider').slider({
+		value: 0,
+		step: 0.25,
+		min: 0.25,
+		max: 180,
+		slide: function(event, ui) {
+			$scope.updateLatSliderDisplayValue(ui.value);
+		},
+	});
+
+	$('#lonSlider').slider({
+		value: 0,
+		step: 0.25,
+		min: 0.25,
+		max: 360,
+		slide: function(event, ui) {
+			$scope.updateLonSliderDisplayValue(ui.value);
+		},
+	});
+
+	$scope.updateLatSliderDisplayValue = function(value) {
+		$scope.latSliderVal = value;
+		$scope.$apply();
+	};
+
+	$scope.updateLonSliderDisplayValue = function(value) {
+		$scope.lonSliderVal = value;
+		$scope.$apply();
+	};
+
+	// Settings for jQuery datepicker directives!
+	$scope.datepickerSettings = {
+		changeMonth: true,
+		changeYear: true,
+	};
+
+	$scope.shouldDisableControls = function() {
+		return (selectedDatasetInformation.getDatasetCount() < 2);
+	}
+
+	$scope.shouldDisableEvaluateButton = function() {
+		return ($scope.shouldDisableControls() || $scope.runningEval);
+	}
+
+	$scope.shouldDisableResultsView = function() {
+		var res = false;
+
+		if ($rootScope.evalResults == "")
+			res = true;
+
+		return res;
+	}
+
+	$scope.runEvaluation = function() {
+		$scope.runningEval = true;
+
+        // Containers for dataset information
+		var obsDatasetIds = [],
+		    obsDatasetParameterIds = [],
+			modelDatasetIds = [],
+			modelDatasetParameterIds = [],
+			modelDatasetTimes = [],
+			modelDatasetLats = [],
+			modelDatasetLons = [];
+
+        // Populate containers with information for each selected dataset
+		for (var i = 0; i < $scope.datasets.length; i++) {
+		    console.log($scope.datasets[i].id)
+			if ($scope.datasets[i]['isObs'] == 1) {
+				obsDatasetIds.push($scope.datasets[i].datasetId)
+				obsDatasetParameterIds.push($scope.datasets[i].id)
+			} else {
+				modelDatasetIds.push($scope.datasets[i].id)
+				modelDatasetParameterIds.push($scope.datasets[i].param)
+				modelDatasetTimes.push($scope.datasets[i].time)
+				modelDatasetLats.push($scope.datasets[i].lat)
+				modelDatasetLons.push($scope.datasets[i].lon)
+			}
+		}
+
+		// TODO At the moment we aren't running all the metrics that the user selected. We're only
+		// running the first available metric that the user provides. If the user un-checks all
+		// metrics then the default of 'bias' is used.
+		var metricToRun = 'bias';
+		var settings = evaluationSettings.getSettings().metrics;
+		for (var i = 0; i < settings.length; i++) {
+			var setting = settings[i];
+
+			if (setting.select) {
+				metricToRun = setting.name;
+				break;
+			}
+		};
+
+        // Prepare information to send to backend service
+		var data = {params: { 
+			'obsDatasetIds'    : obsDatasetIds,
+			'obsParameterIds'  : obsDatasetParameterIds,
+			
+			'startTime'        : $scope.displayParams.start + " 00:00:00",
+			'endTime'          : $scope.displayParams.end + " 00:00:00",
+			'latMin'           : $scope.displayParams.latMin,
+			'latMax'           : $scope.displayParams.latMax,
+			'lonMin'           : $scope.displayParams.lonMin,
+			'lonMax'           : $scope.displayParams.lonMax,
+			
+			'filelist'         : modelDatasetIds,
+			'modelVarName'     : modelDatasetParameterIds,
+			'modelTimeVarName' : modelDatasetTimes,
+			'modelLatVarName'  : modelDatasetLats,
+			'modelLonVarName'  : modelDatasetLons,
+			
+			'regridOption'     : ((evaluationSettings.getSettings().spatialSelect.isObs) ? 'obs' : 'model'),
+			'regridBasis'      : evaluationSettings.getSettings().spatialSelect.id,
+			'timeRegridOption' : evaluationSettings.getSettings().temporal.selected,
+			'metricOption'     : metricToRun,   // Should be a list of metrics to run
+			'subregionFile'    : evaluationSettings.getSettings().subregionFile,
+			'callback'         : 'JSON_CALLBACK',
+		}};
+
+		$http.jsonp($rootScope.baseURL + '/rcmes/run/', data).
+		success(function(data) {
+			var evalWorkDir = data['evalWorkDir'];
+
+			$scope.runningEval = false;
+
+			$timeout(function() {
+				if (evalWorkDir !== undefined) {
+					window.location = "#/results/"+evalWorkDir;
+				} else {
+					window.location = "#/results";
+				}
+			}, 100);
+			
+		}).error(function() {
+			$scope.runningEval = false;
+		});
+	};
+
+	// Check the Parameter selection boxes after the user has changed input to ensure that valid
+	// values were entered
+	$scope.checkParameters = function() {
+		if (parseFloat($scope.displayParams.latMin) < parseFloat($scope.latMin))
+			$scope.displayParams.latMin = $scope.latMin;
+
+		if (parseFloat($scope.displayParams.latMax) > parseFloat($scope.latMax))
+			$scope.displayParams.latMax = $scope.latMax;
+
+		if (parseFloat($scope.displayParams.lonMin) < parseFloat($scope.lonMin)) 
+			$scope.displayParams.lonMin = $scope.lonMin;
+
+		if (parseFloat($scope.displayParams.lonMax) > parseFloat($scope.lonMax)) 
+			$scope.displayParams.lonMax = $scope.lonMax;
+
+		if ($scope.displayParams.start < $scope.start) 
+			$scope.displayParams.start = $scope.start;
+
+		if ($scope.displayParams.end > $scope.end)
+			$scope.displayParams.end = $scope.end;
+
+		$scope.$apply();
+		$rootScope.$broadcast('redrawOverlays', []);
+	}
+
+	$scope.unwatchDatasets = $scope.$watch('datasets', 
+		function() { 
+			var numDatasets = $scope.datasets.length;
+			$scope.displayParams.areValid = false;
+			$scope.areInUserRegridState = false;
+
+ 			if (numDatasets) {
+				var latMin        = -90,
+					latMax        = 90,
+					lonMin        = -180,
+					lonMax        = 180,
+					start         = "1980-01-01 00:00:00",
+					end           = "2030-01-01 00:00:00",
+					datasetRegrid = false;
+ 				// Get the valid lat/lon range in the selected datasets.
+ 				for (var i = 0; i < numDatasets; i++) {
+ 					var curDataset = $scope.datasets[i];
+ 	
+ 					latMin = (curDataset['latlonVals']['latMin'] > latMin) ? curDataset['latlonVals']['latMin'] : latMin;
+ 					latMax = (curDataset['latlonVals']['latMax'] < latMax) ? curDataset['latlonVals']['latMax'] : latMax;
+ 					lonMin = (curDataset['latlonVals']['lonMin'] > lonMin) ? curDataset['latlonVals']['lonMin'] : lonMin;
+ 					lonMax = (curDataset['latlonVals']['lonMax'] < lonMax) ? curDataset['latlonVals']['lonMax'] : lonMax;
+ 					start = (curDataset['timeVals']['start'] > start) ? curDataset['timeVals']['start'] : start;
+ 					end = (curDataset['timeVals']['end'] < end) ? curDataset['timeVals']['end'] : end;
+
+					datasetRegrid = datasetRegrid || curDataset.regrid;
+
+				}
+
+				$scope.areInUserRegridState = !datasetRegrid
+			}
+
+			// Update the display parameters with the new valid overlap that we've found!
+			$scope.displayParams.latMin = latMin;
+			$scope.displayParams.latMax = latMax;
+			$scope.displayParams.lonMin = lonMin;
+			$scope.displayParams.lonMax = lonMax;
+			$scope.displayParams.start = (typeof start == 'undefined') ? "" : start.split(" ")[0];
+			$scope.displayParams.end = (typeof end == 'undefined') ? "" : end.split(" ")[0];
+
+			// Update the local store values!
+			$scope.latMin = latMin;
+			$scope.latMax = latMax;
+			$scope.lonMin = lonMin;
+			$scope.lonMax = lonMax;
+			$scope.start = (typeof start == 'undefined') ? "" : start.split(" ")[0];
+			$scope.end = (typeof end == 'undefined') ? "" : end.split(" ")[0];
+
+			$scope.displayParams.areValid = true;
+			$rootScope.$broadcast('redrawOverlays', []);
+		}, true);
+}]);

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/RcmedSelectionCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/RcmedSelectionCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/RcmedSelectionCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/RcmedSelectionCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+App.Controllers.controller('RcmedSelectionCtrl', ['$rootScope', '$scope', '$http', '$timeout', 'selectedDatasetInformation', 
+function($rootScope, $scope, $http, $timeout, selectedDatasetInformation) {
+	// Grab a copy of the datasets so we can display a count to the user!
+	$scope.datasetCount = selectedDatasetInformation.getDatasets();
+	$scope.fileAdded = false;
+
+	$scope.getObservations = function() {
+		$http.jsonp($rootScope.baseURL + '/getObsDatasets?callback=JSON_CALLBACK').
+			success(function(data) {
+				$scope.availableObs = data;
+				$scope.availableObs.splice(0, 0, {longname: 'Please select an option'});
+				$scope.datasetSelection = $scope.availableObs[0];
+			}).
+			error(function(data) {
+				$scope.availableObs = ["Unable to query RCMED"]
+			});
+	};
+
+	$scope.getObservationTimeRange = function(datasetID) {
+		var times = {
+			'1' : {'start' : '1989-01-01 00:00:00','end' : '2009-12-31 00:00:00'},	// ERA-Interim
+			'2' : {'start' : '2002-08-31 00:00:00','end' : '2010-01-01 00:00:00'},	// AIRS
+			'3' : {'start' : '1998-01-01 00:00:00','end' : '2010-01-01 00:00:00'},	// TRMM
+			'4' : {'start' : '1948-01-01 00:00:00','end' : '2010-01-01 00:00:00'},	// URD
+			'5' : {'start' : '2000-02-24 00:00:00','end' : '2010-05-30 00:00:00'},	// MODIS
+			'6' : {'start' : '1901-01-01 00:00:00','end' : '2006-12-01 00:00:00'}   // CRU
+		};
+
+		return ((datasetID in times) ? times[datasetID] : false);
+	};
+
+	$scope.dataSelectUpdated = function() {
+		var urlString = $rootScope.baseURL + '/getDatasetParam?dataset=' + 
+							$scope.datasetSelection["shortname"] + 
+							"&callback=JSON_CALLBACK";
+		$http.jsonp(urlString).
+			success(function(data) {
+				$scope.retrievedObsParams = data;
+				if ($scope.retrievedObsParams.length > 1) 
+					$scope.retrievedObsParams.splice(0, 0, {shortname: 'Please select a parameter'});
+				$scope.parameterSelection = $scope.retrievedObsParams[0];
+			});
+	};
+
+	$scope.addObservation = function() {
+		// This is a horrible hack for temporarily getting a valid time range
+		// for the selected observation. Eventually we need to handle this more
+		// elegantly than indexing into an array...
+		var timeRange = $scope.getObservationTimeRange($scope.datasetSelection["dataset_id"]);
+
+		var newDataset = {};
+
+		newDataset['isObs'] = 1;
+		// Save the dataset id (the important part) and name (for display purposes)
+		newDataset['datasetId'] = $scope.datasetSelection['dataset_id'];
+		newDataset['name'] = $scope.datasetSelection['longname'];
+		// Save the parameter id (the important part) and name (for display purposes)
+		newDataset['id']    = $scope.parameterSelection['parameter_id'];
+		newDataset['param'] = $scope.parameterSelection['parameter_id'];
+		newDataset['paramName'] = $scope.parameterSelection['longname'];
+		// Save the (fake) lat/lon information. We test with the TRMM dataset. RCMED currently
+		// doesn't return bounding information. This functionality is being added soon. When that
+		// is the case these hard coded values should be removed.
+		newDataset['latlonVals'] = {"latMin": -49.875, "latMax": 49.875, "lonMin": -179.875, "lonMax": 179.875};
+		// Set some defaults for lat/lon variable names. This just helps us display stuff later.
+		newDataset['lat'] = "N/A";
+		newDataset['lon'] = "N/A";
+		// Save time range information. If we don't have saved data for this observation then
+		// we set the values to extreme values so they'll be ignored when calculating overlaps.
+		newDataset['timeVals'] = {"start": (timeRange) ? timeRange['start'] : "1901-01-01 00:00:00",
+								  "end": (timeRange) ? timeRange['end'] : "2050-01-01 00:00:00"};
+		// Set a default for the time variable names for display convenience.
+		newDataset['time'] = "N/A";
+
+		selectedDatasetInformation.addDataset(newDataset);
+
+		// Clear the user selections by requery-ing RCMED. This is really hacky, but it works for now...
+		$scope.availableObs = [];
+		$scope.retrievedObsParams = [];
+		$scope.getObservations();
+
+		// Display a confirmation message for a little bit
+		$scope.fileAdded = true;
+		$timeout(function() {
+			$scope.fileAdded = false;
+		}, 2000);
+	};
+
+	// Grab the available observations from RCMED
+	$scope.getObservations();
+}]);

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ResultCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ResultCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ResultCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ResultCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Controller for result page
+App.Controllers.controller('ResultCtrl', ['$rootScope', '$scope', '$http',
+function($rootScope, $scope, $http) {
+
+    $scope.results = [];
+
+    // Get all evaluation directories
+    $http.jsonp($rootScope.baseURL + '/getResultDirInfo?callback=JSON_CALLBACK')
+    .success(function(data) {
+      var removeItem = "/cache";
+      data.splice( $.inArray(removeItem,data) ,1 );
+      $scope.results = data.sort().reverse();
+    });
+
+}]);

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ResultDetailCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ResultDetailCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ResultDetailCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/ResultDetailCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Controller for result page
+App.Controllers.controller('ResultDetailCtrl', ['$rootScope', '$scope', '$http', '$stateParams',
+function($rootScope, $scope, $http, $stateParams) {
+
+	// Grab all figures 
+	$scope.result = $stateParams.resultId;
+	
+	$http.jsonp($rootScope.baseURL + '/getResults//' + $scope.result + '?callback=JSON_CALLBACK')
+	.success(function(data) {
+	  if (data.length < 1){
+		$scope.figures = null;
+		$scope.alertMessage = "No results found.";
+		$scope.alertClass = "alert alert-danger";
+	  } else {
+		$scope.figures = data;
+	  }
+	});
+
+}]);

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/SettingsCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/SettingsCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/SettingsCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/SettingsCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+App.Controllers.controller('SettingsCtrl', ['$scope', 'evaluationSettings', 'selectedDatasetInformation',
+function($scope, evaluationSettings, selectedDatasetInformation) {
+	$scope.settings = evaluationSettings.getSettings();
+	$scope.datasets = selectedDatasetInformation.getDatasets();
+}]);

Propchange: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/SettingsCtrl.js
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/TimelineCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/TimelineCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/TimelineCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/TimelineCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,92 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.You may obtain a copy of the License at
+// 
+// http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Controller for the OCW Timeline Widget
+App.Controllers.controller('TimelineCtrl', ['$rootScope', '$scope', 'selectedDatasetInformation', 'regionSelectParams',
+function($rootScope, $scope, selectedDatasetInformation, regionSelectParams) {
+	$scope.datasets = selectedDatasetInformation.getDatasets();
+	$scope.regionParams = regionSelectParams.getParameters();
+
+	$scope.updateTimeline = function() {
+ 		// Clear timeline data if it exists
+ 		if ("timeline" in $rootScope) {
+ 			$rootScope.timeline.deleteAllItems();
+ 		}
+
+		// Don't process if no datasets have been added
+		if ($scope.datasets.length == 0 || !("timeline" in $rootScope))
+			return;
+ 		
+		// Create DataTable to add data to timeline
+		var data = new google.visualization.DataTable();
+		data.addColumn('datetime', 'start');
+		data.addColumn('datetime', 'end');
+		data.addColumn('string', 'content');
+
+		// Loop through datasets and find the overlapping start/end time range
+		var start = $scope.datasets[0].timeVals.start;
+		var end = $scope.datasets[0].timeVals.end;
+		for (var i = 0; i < $scope.datasets.length; i++) {
+			var possibleNewStart = $scope.datasets[i].timeVals.start;
+			var possibleNewEnd = $scope.datasets[i].timeVals.end;
+
+			start = (possibleNewStart > start) ? possibleNewStart : start;
+			end = (possibleNewEnd < end) ? possibleNewEnd : end;
+		}
+
+		// Set the timeline extent to the overlapping time range
+		//
+		// NOTE: The month value substring is expected to be 0-based (hence the -1)
+		$rootScope.timeline.setVisibleChartRange(new Date(start.substr(0, 4), start.substr(5, 2) - 1, start.substr(8, 2)),
+												 new Date(end.substr(0, 4), end.substr(5, 2) - 1, end.substr(8, 2)));
+
+		// Add user selected bounds to timeline
+		if ($scope.regionParams.areValid) {
+
+			var userStart 	= $scope.regionParams.start;
+			var userEnd 	= $scope.regionParams.end;
+
+			// Add color to user selected bounds
+			var style = 'background-color: #000000; border: 2px solid;';
+			var ocwBar = '<div class="ocw-bar timeline-event-range" style="' + style + '"></div>';
+			
+			// Add row to DataTable: object with start and end date
+			// note: subtract one from month since indexes from 0 to 11
+			data.addRow([new Date(userStart.substr(0,4), userStart.substr(5,2)-1, userStart.substr(8,2)), 
+						new Date(userEnd.substr(0,4), userEnd.substr(5,2)-1, userEnd.substr(8,2)),
+						ocwBar ]);
+		}
+		
+		var options = {
+				"width": "100%",
+				"showCurrentTime": false,
+				"moveable": false,
+				"zoomable": false,
+		};
+		
+		// Draw timeline with data (DataTable) and options (a name-value map) 
+		$rootScope.timeline.draw(data, options);
+	};
+
+	$scope.$on('redrawOverlays', function(event, parameters) {
+		$scope.updateTimeline();
+	});
+
+	$scope.$watch('datasets', function() {
+		$scope.updateTimeline();
+	}, true);
+}]);

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/WorldMapCtrl.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/WorldMapCtrl.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/WorldMapCtrl.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/controllers/WorldMapCtrl.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Controller for the world map
+App.Controllers.controller('WorldMapCtrl', ['$rootScope', '$scope', 'selectedDatasetInformation', 'regionSelectParams',
+function($rootScope, $scope, selectedDatasetInformation, regionSelectParams) {
+	$scope.datasets = selectedDatasetInformation.getDatasets();
+	$scope.regionParams = regionSelectParams.getParameters();
+
+	$scope.updateMap = function() {
+ 		// Clear Group of layers from map if it exists
+ 		if ("rectangleGroup" in $rootScope) {
+ 			$rootScope.rectangleGroup.clearLayers();
+ 		}
+
+		// Don't process if we don't have any datasets added or if the map doesn't exist!!
+		if ($scope.datasets.length == 0 || !("map" in $rootScope))
+			return;
+ 		
+		// Create a group that we'll draw overlays to
+		$rootScope.rectangleGroup = L.layerGroup();
+		// Add rectangle Group to map
+		$rootScope.rectangleGroup.addTo($rootScope.map);
+
+		// Calculate the overlap region and set the map to show the new overlap
+		var latMin = -90,
+			latMax = 90,
+			lonMin = -180,
+			lonMax = 180;
+
+		// Get the valid lat/lon range in the selected datasets.
+		for (var i = 0; i < selectedDatasetInformation.getDatasetCount(); i++) {
+			var curDataset = $scope.datasets[i];
+
+			latMin = (curDataset['latlonVals']['latMin'] > latMin) ? curDataset['latlonVals']['latMin'] : latMin;
+			latMax = (curDataset['latlonVals']['latMax'] < latMax) ? curDataset['latlonVals']['latMax'] : latMax;
+			lonMin = (curDataset['latlonVals']['lonMin'] > lonMin) ? curDataset['latlonVals']['lonMin'] : lonMin;
+			lonMax = (curDataset['latlonVals']['lonMax'] < lonMax) ? curDataset['latlonVals']['lonMax'] : lonMax;
+		}
+
+		var overlapBounds = [[latMax, lonMin], [latMin, lonMax]];
+		$rootScope.map.fitBounds(overlapBounds, {padding: [0, 0]});
+
+		// Draw border around overlap region
+		var overlapBorder = L.rectangle(overlapBounds, {
+			color: '#000000',
+			opacity: 1.0,
+			fill: false,
+			weight: 2,
+			dashArray: "10 10",
+		});
+
+		$rootScope.rectangleGroup.addLayer(overlapBorder);
+
+		// Draw user selected region
+		if ($scope.regionParams.areValid) {
+
+			var bounds = [[$scope.regionParams.latMax, $scope.regionParams.lonMin],
+						  [$scope.regionParams.latMin, $scope.regionParams.lonMax]];
+
+			var polygon = L.rectangle(bounds, {
+				color: '#000000',
+				opacity: .3,
+				stroke: false,
+				fill: true,
+			});
+
+			$rootScope.rectangleGroup.addLayer(polygon);
+		}
+	};
+
+	$scope.$on('redrawOverlays', function(event, parameters) {
+		$scope.updateMap();
+	});
+
+	$scope.$watch('datasets', function() {
+		$scope.updateMap();
+	}, true);
+}]);

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/directives/BootstrapModal.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/directives/BootstrapModal.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/directives/BootstrapModal.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/directives/BootstrapModal.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Directive for inserting bootstrap modals
+App.Directives.directive('bootstrapModal', function($timeout) {
+	var link = function(scope, elem, attrs) {
+		var escapeEvent;
+		var openModal;
+		var closeModal;
+
+		escapeEvent = function(e) {
+			if (e.which == 27)
+				closeModal();
+		}
+
+		openModal = function(event, toggleBackground, toggleKeyboardEscape) {
+			// Grab the current modal tag based on the modalId attribute in the bootstrapModal tag
+			var modal = $('#' + attrs.modalId);
+
+			// Make all the modal's children of class "close" call the appropriate function for closing!
+			$('.close', modal).bind('click', closeModal);
+
+			modal.modal({
+				show: true,
+				backdrop: toggleBackground,
+				keyboard: toggleKeyboardEscape,
+			});
+		};
+
+		closeModal = function(event) {
+			$('#' + attrs.modalId).modal('hide');
+			
+		};
+
+		// We need to bind the close and open modal events so outside elements can trigger the modal.
+		// This has to wait until the template has been fully inserted, so just wait a bit of time
+		// before we set them. I'm sure there's a better way of handling this...
+		$timeout(function() {
+			$('#' + attrs.modalId).
+				bind('modalOpen', openModal).
+				bind('modalClose', closeModal);
+		}, 100);
+	};
+
+	return {
+		link: link,
+		replace: true,
+		restrict: 'E',
+		scope: {
+			modalId: '@' 
+		},
+		template: '<div id="{{modalId}}" class="modal hide fade" tabindex="-1"><div ng-transclude></div></div>',
+		transclude: true
+	};
+});

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/directives/BootstrapModalOpen.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/directives/BootstrapModalOpen.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/directives/BootstrapModalOpen.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/directives/BootstrapModalOpen.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// This directive processes bootstrap-modal-open attributes. This lets the user bind 
+// the opening of a specific modal to a button/link. It also lets the user specify
+// what features the modal should have. The user can turn off the semi-opaque background
+// by having the background attribute set to 'false'. The user can also turn off the
+// ability to close the modal with ESC by having the keyboard attribute set to 'false'.
+App.Directives.directive('bootstrapModalOpen', function() {
+	return {
+		restrict: 'A',
+		link: function(scope, elem, attrs) {
+			// Default to showing the background if the user didn't specify a value for this.
+			var hasBackground = (attrs.background === undefined ? true : (attrs.background == "true"));
+			// Enable keyboard closing of modal with escape key.
+			var hasKeyboardEscape = (attrs.keyboard === undefined ? true : (attrs.keyboard == "true"));
+
+			$(elem).bind('click', function() {
+				$('#' + attrs.bootstrapModalOpen).trigger('modalOpen', [hasBackground, hasKeyboardEscape]);
+			});
+		}
+	};
+});

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/directives/LeafletMap.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/directives/LeafletMap.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/directives/LeafletMap.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/directives/LeafletMap.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Directive for dealing with the Leaflet map
+App.Directives.directive('leafletMap', function($rootScope) {
+	return {
+		restrict: 'E',
+		replace: true,
+		template: '<div></div>',
+		link: function(scope, element, attrs) {
+			$rootScope.map = L.map(attrs.id, {
+				center: [40, 0],
+				zoom: 2,
+				scrollWheelZoom: false,
+				attributionControl: false,
+				worldCopyJump: true,
+			});
+
+			//create a CloudMade tile layer and add it to the map
+			L.tileLayer('http://{s}.tile.cloudmade.com/57cbb6ca8cac418dbb1a402586df4528/997/256/{z}/{x}/{y}.png', {}).addTo($rootScope.map);
+		}
+	};
+});

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/directives/OnBlur.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/directives/OnBlur.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/directives/OnBlur.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/directives/OnBlur.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// The onBlur directive calls a passed function when a field's "blur" event is called.
+// The function should be passed as part of the "on-blur" attribute and be defined in
+// the containing scope.
+//
+// Consider the test function "testFunc". If you wanted this to run on the blur event
+// for an input box you would use the following:
+//   <input type="text" on-blur="testFunc();" />
+App.Directives.directive('onBlur', function() {
+	return {
+        restrict: 'A',
+        link: function($scope, $elem, $attrs) {
+            $elem.bind('blur', function() {
+				$scope.$eval($attrs.onBlur);
+			});
+        },
+    };
+ });

Propchange: incubator/climate/trunk/ocw-ui/frontend/app/js/directives/OnBlur.js
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/directives/PredictiveFileBrowserInput.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/directives/PredictiveFileBrowserInput.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/directives/PredictiveFileBrowserInput.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/directives/PredictiveFileBrowserInput.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,306 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+// Setup a text input that the user will use to input a path to a local file.
+App.Directives.directive('predictiveFileBrowserInput', function() {
+	var link = function($scope, $elem, $attrs) {
+		$scope.autocomplete = [];
+		
+		// Set id to use this directive correctly in multiple places
+		$scope.id = 'autoCompletePath'+ $elem.context.id
+		/*
+		 * We need a place to dump our auto-completion options
+		 */
+		$($elem).parent().append('<ul id="' + $scope.id +'"><ul>');
+
+		// Handle user clicks on auto-complete path options
+		$(document).on('click', '#' +$scope.id+ ' li span', function(e) {
+			// Set the input text box's value to that of the user selected path
+			var val = $(e.target).text();
+			$($elem).val(val);
+			// Need to trigger the input box's "input" event so Angular updates the model!
+			$elem.trigger('input'); 
+			
+			// If the user selected a directory, find more results..
+			if (val[val.length - 1] == '/') {
+				$scope.fetchFiles($($elem).val());
+			// Otherwise, remove the auto-complete options...
+			} else {
+				$('#' +$scope.id+ ' li').remove();
+			}
+		});
+
+		/*
+		 * Handle key-down events on the input box
+		 *
+		 * We need to ignore <TAB> presses here so we can auto-complete with <TAB>.
+		 * If we don't ignore here then <TAB> will move the user to the next field
+		 * in the form and our common-prefix-fill won't work later.
+		 */
+		$($elem).keydown(function(e) {
+			var code = e.keyCode || e.which;
+			var BACKSPACE = 8,
+				TAB = 9;
+
+			if (code == TAB)
+				return false;
+		});
+
+		/*
+		 * Handle key-up events on the input box
+		 */
+		$($elem).keyup(function(e) {
+			var code = e.keyCode || e.which;
+			var BACKSPACE = 8,
+				TAB = 9,
+				FORWARD_SLASH = 191;
+
+			if (code === FORWARD_SLASH) {
+				// Fetch new directory information from the server.
+				$scope.fetchFiles($(this).val());
+			} else if (code === TAB) {
+				// Attempt to auto-fill for the user.
+				$scope.handleTabPress();
+			} else if (code == BACKSPACE) {
+				// Need to properly handle the removal of directory information
+				// and the displaying of auto-complete options
+				$scope.handleBackSpace();
+			} else {
+				// Filter auto-complete options based on user input..
+				$scope.handleMiscKeyPress();
+			}
+
+			// This is being used so we can handle backspacing. The user might hold
+			// down the backspace key or select a section of text and delete. This allows
+			// us to compare the result to its prior state, which makes handling
+			// backspaces easier.
+			$scope.lastInputContents = $elem.val();
+		});
+
+		/*
+		 * Grab additional path information from the web-server
+		 *
+		 * Params:
+		 *		path - The path to get a directory listing of.
+		 */
+		// TODO Make this use $HTTP
+		$scope.fetchFiles = function(path) {
+			$.get($scope.baseURL + '/getDirInfo/' + path, {},
+				 function(data) {
+					 $scope.setNewData(data);
+					 $scope.updateAutoComplete();
+				 }, 'json');
+		};
+
+		/*
+		 * Grab additional path information from the web-server and filter the
+		 * results based on the current input text.
+		 *
+		 * Params:
+		 *		path - The path to get a directory listing of.
+		 *
+		 * This is needed to handle deletion of selected text. It is possible that
+		 * the user will select text and delete only part of a word. The results
+		 * need to be filtered based on this partial input.
+		 */
+		// TODO Why isn't this using $http?!?!?! Because I copy and pasted!!!!
+		$scope.fetchFilesAndFilter = function(path) {
+			$.get($scope.baseURL + '/getDirInfo/' + path, {},
+				 function(data) {
+					 $scope.setNewData(data);
+					 $scope.filterResults();
+					 $scope.updateAutoComplete();
+				 }, 'json');
+		};
+
+		/*
+		 * Handle directory data from the server.
+		 *
+		 * We store the entire directory information along with the remaining
+		 * possible options given the users current input. This lets us avoid
+		 * unnecessary calls to the server for directory information every time
+		 * the user deletes something.
+		 */
+		$scope.setNewData = function(data) {
+			$scope.autocomplete = data.sort();
+			$scope.possibleCompletes = $scope.autocomplete;
+		};
+
+		/* 
+		 * Handle <TAB> presses.
+		 *
+		 * Attempt to auto-complete options when the user presses <TAB>.
+		 */
+		$scope.handleTabPress = function() {
+			// If there's only one option available there's no points in trying to
+			// find a common prefix! Just set the value!
+			if ($scope.possibleCompletes.length === 1) {
+				$elem.val($scope.possibleCompletes[0]);
+
+				// Make sure more options are displayed if a directory was selected.
+				$scope.checkForMoreOptions();
+				$scope.updateAutoComplete();
+				return;
+			}
+
+			// Find the greatest common prefix amongst the remaining choices and set
+			// the input text to it.
+			var prefix = $scope.getLargestCommonPrefix($scope.possibleCompletes);
+			$elem.val(prefix);
+			$scope.updateAutoComplete();
+		};
+
+		/*
+		 * Handle Backspacing and option displaying.
+		 *
+		 * The auto-complete options needs to be displayed correctly when the user
+		 * removes directory information.
+		 */
+		$scope.handleBackSpace = function() {
+			var curInputVal = $elem.val();
+
+			// If the user deletes everything in the input box all we need to do
+			// is make sure that the auto-complete options aren't displayed.
+			if (curInputVal.length === 0) {
+				$('#' +$scope.id+ ' li').remove();
+				return;
+			}
+
+			// Figure out how much text the user removed from the input box.
+			var lengthDiff = $scope.lastInputContents.length - curInputVal.length;
+			// Grab the removed text.
+			var removedText = $scope.lastInputContents.substr(-lengthDiff);
+
+			// If the user deleted over a directory we need to fetch information on the
+			// previous directory for auto-completion.
+			if (removedText.indexOf('/') !== -1) {
+				var lastSlashIndex = curInputVal.lastIndexOf('/');
+
+				// If the remaining path still contains a directory...
+				if (lastSlashIndex !== -1) {
+					// Grab the section of the path that points to a valid directory,
+					// fetch the listing, and update the results.
+					var pathToSearch = curInputVal.slice(0, lastSlashIndex + 1);
+					$scope.fetchFilesAndFilter(pathToSearch);
+				} else {
+					// Delete the old auto-complete information in the case where the user
+					// completely removed path information.
+					$('#' +$scope.id+ ' li').remove();
+				}
+			} else {
+				// Otherwise, we just need to filter results based on the remaining input.
+				$scope.filterResults();
+				$scope.updateAutoComplete();
+			}
+		};
+
+		/* 
+		 * Handle all other key presses in the input box
+		 *
+		 * Filter the auto-complete options as the user types to ensure that only options
+		 * which are possible given the current input text are still displayed.
+		 */
+		$scope.handleMiscKeyPress = function() {
+			// Safely exit when there are no options available.
+			if ($scope.autocomplete === [])
+				return;
+
+			// Otherwise, filter the results.
+			$scope.filterResults();
+			$scope.updateAutoComplete();
+		};
+
+		/* 
+		 * When a path is auto-completed with <TAB> we need to check to see if it points
+		 * to a directory. If it does, we still need to fetch results!
+		 */
+		$scope.checkForMoreOptions = function() {
+			var path = $elem.val();
+			if (path[path.length - 1] === '/') {
+				$scope.fetchFiles(path);
+			}
+		};
+
+		/* 
+		 * Calculate the greatest common prefix of the passed options.
+		 *
+		 * Params:
+		 *		Options - An array of strings in which the greatest common prefix
+		 *				  should be found
+		 *
+		 * Returns:
+		 *		The greatest common prefix of the strings.
+		 *
+		 *
+		 * Note - For us, there will always be a prefix of at least '/' since this can't
+		 * possible be called without the users entering a starting directory. As a result,
+		 * we don't explicitly handle the case where there is 0 length common prefix.
+		 */
+		$scope.getLargestCommonPrefix = function(options) {
+			var index = 1;
+			var shortestString = options.reduce(function(a, b) { return a.length < b.length ? a : b; });
+			var longestString = options.reduce(function(a, b) { return a.length > b.length ? a : b; });
+			var	substringToCheck = shortestString[0];
+
+			while (longestString.indexOf(substringToCheck) !== -1) {
+				substringToCheck = shortestString.slice(0, ++index);
+			}
+
+			return longestString.slice(0, index - 1);
+		};
+
+		/* 
+		 * Filter the auto-complete options based on the current input.
+		 */
+		$scope.filterResults = function() {
+			$scope.possibleCompletes = $scope.autocomplete.filter(function(item, index, array) {
+				return (~item.indexOf($($elem).val()));
+			});
+
+			$scope.possibleCompletes.sort();
+		};
+
+		/*
+		 * Update the display of auto-complete options.
+		 */
+		$scope.updateAutoComplete = function() {
+			// Remove all the existing options
+			$('#' +$scope.id+ ' li').remove();
+
+			// We don't need to show anything if the user has completely selected
+			// the only existing option available.
+			if ($scope.possibleCompletes.length === 1) {
+				if ($scope.possibleCompletes[0] === $elem.val()) {
+					return;
+				}
+			}
+
+			// Display all the possible completes
+			$.each($scope.possibleCompletes, function(i, v) {
+				$('#' +$scope.id+ '').append($('<li>').html($('<span>').text(v)));
+			});
+		};
+	};
+
+	return {
+		link: link,
+		scope: true,
+		restrict: 'A'
+	};
+});

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/directives/PreviewMap.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/directives/PreviewMap.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/directives/PreviewMap.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/directives/PreviewMap.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+App.Directives.directive('previewMap', function($rootScope) {
+	return {
+		restrict: 'A',
+		replace: true,
+		scope: {dataset: '=previewMap', index: '=index'},
+		template: '<div id="{{dataset.name}}" class="preview-map"></div>',
+		replace: true,
+		link: function(scope, element, attrs) {
+
+			// Any attribute that contains {{}} interpolation will be set to null in the attrs
+			// parameter during the link function since the first $digest since the compilation
+			// has yet to run to evaluate it! We can't run a $digest in the middle of compilation,
+			// so using an $observe (or $watch) is the best way to get the values.
+			attrs.$observe('id', function(newId) {
+				var map = L.map(attrs.id, {
+					zoom: 0,
+					scrollWheelZoom: false,
+					zoomControl: false,
+					attributionControl: false,
+					worldCopyJump: true,
+				});
+
+				//create a CloudMade tile layer and add it to the map
+				L.tileLayer('http://{s}.tile.cloudmade.com/57cbb6ca8cac418dbb1a402586df4528/997/256/{z}/{x}/{y}.png', {}).addTo(map);
+
+				// Zoom the map to the dataset bound regions (or at least try our best to do so)
+				var datasetBounds = [[scope.dataset.latlonVals.latMax, scope.dataset.latlonVals.lonMin], 
+									 [scope.dataset.latlonVals.latMin, scope.dataset.latlonVals.lonMax]];
+				map.fitBounds(datasetBounds, {});
+
+				// Draw a colored overlay on the region of the map
+				var maplatlon = scope.dataset.latlonVals;
+				var bounds = [[maplatlon.latMax, maplatlon.lonMin], [maplatlon.latMin, maplatlon.lonMax]];
+
+				var polygon = L.rectangle(bounds,{
+					stroke: false,
+					fillColor: $rootScope.fillColors[1],
+					fillOpacity: 0.6
+				});
+
+				// Add layer to Group
+				var rectangleGroup = L.layerGroup();
+				rectangleGroup.addLayer(polygon);
+
+				// Add the overlay to the map
+				rectangleGroup.addTo(map);
+			});
+		}
+	};
+});

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/directives/Timeline.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/directives/Timeline.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/directives/Timeline.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/directives/Timeline.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,44 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.You may obtain a copy of the License at
+// 
+// http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Directive for dealing with the Leaflet map
+App.Directives.directive('timeline', function($rootScope, $window) {
+	return {
+		restrict: 'C',
+		replace: true,
+		transclude: true,
+		template: '<div id="OCWtimeline"></div>',
+		link: function(scope, element, attrs) {
+			// Instantiate timeline object.
+			$rootScope.timeline = new links.Timeline(document.getElementById('OCWtimeline'));
+
+			// Redraw the timeline whenever the window is resized
+			angular.element($window).bind('resize', function() {
+				$rootScope.timeline.checkResize();
+			});
+
+			var options = {
+				"width": "100%",
+				"showCurrentTime": false,
+				"moveable": false,
+				"zoomable": false
+			};
+
+			$rootScope.timeline.draw([], options);
+		}
+	}
+});

Added: incubator/climate/trunk/ocw-ui/frontend/app/js/filters/ISODateToMiddleEndian.js
URL: http://svn.apache.org/viewvc/incubator/climate/trunk/ocw-ui/frontend/app/js/filters/ISODateToMiddleEndian.js?rev=1562255&view=auto
==============================================================================
--- incubator/climate/trunk/ocw-ui/frontend/app/js/filters/ISODateToMiddleEndian.js (added)
+++ incubator/climate/trunk/ocw-ui/frontend/app/js/filters/ISODateToMiddleEndian.js Tue Jan 28 22:18:16 2014
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http: *www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+**/
+
+'use strict';
+
+// Convert a date in ISO format (or slightly modified such that 'T' is replace by ' ') into
+// a 'Middle Endian'/U.S. style date.
+App.Filters.filter('ISODateToMiddleEndian', function() {
+	return function(input) {
+		var original = input;
+
+		// Strip whitespace from the start and end of the string
+		input = input.replace(/(^\s+|\s+$)/g, '');
+
+		// ISO Standard says time is separated from Date with a 'T'. Our timestamps
+		// slightly modify that and use a space. We'll check for both here and prefer
+		// to split on a 'T' if it's available.
+		if (input.indexOf('T') != -1 || input.indexOf(' ') != -1) {
+			input = (input.indexOf('T') != -1) ? input.split('T')[0] : input.split(' ')[0];
+		} 
+		
+		// The components of the date should be split with hyphens. If we can't find them
+		// then the string is poorly formed.
+		if (input.indexOf('-') == -1 || input.split('-').length - 1 != 2) {
+			return original;
+		}
+
+		// At this point the date is probably valid and we should try to convert it!
+		var components = input.split('-');
+		return (components[1] + "/" + components[2] + "/" + components[0]);
+	};
+});



Mime
View raw message