<!doctype html>
<html data-ng-app="myApp" data-ng-csp="">
<head>
<meta charset="UTF-8">
<title>Presently</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div class="container">
<div data-ng-view></div>
<div id="actionbar">
<ul class="list-inline">
<li><a class="glyphicon glyphicon-home" href="#/"></a></li>
<li><a class="glyphicon glyphicon-list" href="#/settings"></a></li>
</ul>
</div>
</div>
<script src="./js/vendor/angular.min.js"></script>
<script src="./js/vendor/angular-route.min.js"></script>
<script src="./js/app.js"></script>
</body>
</html>
<h2>Settings</h2>
<form ng-submit="save()">
<input type="text"
ng-model="user.location"
timezone="user.timezone"
auto-fill="fetchCities"
autocomplete="off"
placeholder="Location" />
<input class="btn btn-primary"
type="submit" value="Save" />
</form>
{
"manifest_version": 2,
"name": "Presently",
"description": "A currently clone",
"version": "0.1",
"permissions": [
"http://api.wunderground.com/api/"
],
"background": {
"scripts": ["js/vendor/angular.min.js"]
},
"content_security_policy": "script-src 'self'; object-src 'self'",
"chrome_url_overrides" : {
"newtab": "tab.html"
}
}
/* Include this file in your html if you are using the CSP mode. */
@charset "UTF-8";
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide {
display: none !important;
}
ng\:form {
display: block;
}
body {
background-color: #eee;
font-family: 'Actor', sans-serif;
color: #444;
}
#datetime {
text-align: center;
}
#datetime h1 {
font-size: 6.1em;
}
#datetime h2 {
font-size: 1.0em;
}
@font-face {
font-family: 'Actor';
src: url('chrome-extension://__MSG_@@extension_id__/fonts/DroidSansMono.ttf');
}
#forecast ul li {
font-size: 4.5em;
text-align: center;
}
#forecast ul li img {
}
#forecast ul li h3 {
font-size: 1.5em;
}
#actionbar {
position: absolute;
bottom: 0.5em;
right: 1.0em;
}
#actionbar a {
font-size: 2.2rem;
color: #000;
}
.typeahead ul {
max-height: 150px;
border: 1px solid #333;
padding: 3px;
overflow: auto;
}
<div>
<div id="datetime">
<h1>{{ date.tz | date:'hh mm ss' }}</h1>
<h2>{{ date.tz | date:'EEEE, MMMM yyyy' }}</h2>
</div>
<div id="forecast">
<ul class="row list-unstyled">
<li ng-repeat="day in weather.forecast.forecastday" class="col-md-3">
<span ng-class="{today: $index == 0}">
<img class="{{ day.icon }}" ng-src="{{ day.icon_url }}" />
<h3>{{ day.high.fahrenheit }}</h3>
<h4 ng-if="$index == 0">Now</h4>
<h4 ng-if="$index != 0">{{ day.date.weekday }}</h4>
</span>
</li>
</ul>
</div>
</div>
angular.module('myApp', ['ngRoute'])
.provider('Weather', function() {
var apiKey = "";
this.getUrl = function(type, ext) {
return "http://api.wunderground.com/api/" +
this.apiKey + "/" + type + "/q/" +
ext + '.json';
};
this.setApiKey = function(key) {
if (key) this.apiKey = key;
};
this.$get = function($q, $http) {
var self = this;
return {
getWeatherForecast: function(city) {
var d = $q.defer();
$http({
method: 'GET',
url: self.getUrl("forecast", city),
cache: true
}).success(function(data) {
d.resolve(data.forecast.simpleforecast);
}).error(function(err) {
d.reject(err);
});
return d.promise;
},
getCityDetails: function(query) {
var d = $q.defer();
$http({
method: 'GET',
url: "http://autocomplete.wunderground.com/aq?query=" +
query
}).success(function(data) {
d.resolve(data.RESULTS);
}).error(function(err) {
d.reject(err);
});
return d.promise;
}
}
}
})
.factory('UserService', function() {
var defaults = {
location: 'autoip'
};
var service = {
user: {},
save: function() {
sessionStorage.presently =
angular.toJson(service.user);
},
restore: function() {
service.user =
angular.fromJson(sessionStorage.presently) || defaults
return service.user;
}
};
service.restore();
return service;
})
.config(function(WeatherProvider) {
WeatherProvider.setApiKey('REPLACE_WITH_YOUR_KEY');
})
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'templates/home.html',
controller: 'MainCtrl'
})
.when('/settings', {
templateUrl: 'templates/settings.html',
controller: 'SettingsCtrl'
})
.otherwise({redirectTo: '/'});
}])
.directive('autoFill', function($timeout, Weather) {
return {
restrict: 'EA',
scope: {
autoFill: '&',
ngModel: '=',
timezone: '='
},
compile: function(tEle, tAttrs) {
var tplEl = angular.element('<div class="typeahead">' +
'<input type="text" autocomplete="off" />' +
'<ul id="autolist" ng-show="reslist">' +
'<li ng-repeat="res in reslist" ' +
'>{{res.name}}</li>' +
'</ul>' +
'</div>');
var input = tplEl.find('input');
input.attr('type', tAttrs.type);
input.attr('ng-model', tAttrs.ngModel);
input.attr('timezone', tAttrs.timezone);
tEle.replaceWith(tplEl);
return function(scope, ele, attrs, ctrl) {
var minKeyCount = attrs.minKeyCount || 3,
timer;
ele.bind('keyup', function(e) {
val = ele.val();
if (val.length < minKeyCount) {
if (timer) $timeout.cancel(timer);
scope.reslist = null;
return;
} else {
if (timer) $timeout.cancel(timer);
timer = $timeout(function() {
scope.autoFill()(val)
.then(function(data) {
if (data && data.length > 0) {
scope.reslist = data;
scope.ngModel = data[0].zmw;
scope.timezone = data[0].tz;
}
});
}, 300);
}
});
// Hide the reslist on blur
input.bind('blur', function(e) {
scope.reslist = null;
scope.$digest();
});
}
}
}
})
.controller('MainCtrl',
function($scope, $timeout, Weather, UserService) {
$scope.date = {};
var updateTime = function() {
$scope.date.tz = new Date(new Date()
.toLocaleString("en-US", {timeZone: $scope.user.timezone}));
$timeout(updateTime, 1000);
}
$scope.weather = {}
$scope.user = UserService.user;
Weather.getWeatherForecast($scope.user.location)
.then(function(data) {
$scope.weather.forecast = data;
});
updateTime();
})
.controller('SettingsCtrl',
function($scope, $location, Weather, UserService) {
$scope.user = UserService.user;
$scope.save = function() {
UserService.save();
$location.path('/');
}
$scope.fetchCities = Weather.getCityDetails;
});