PageRenderTime 62ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/FarmasWebSite/Content/features/weather/weather.js

https://bitbucket.org/farmas/farmas-sandbox
JavaScript | 256 lines | 229 code | 24 blank | 3 comment | 9 complexity | a0ab913b86af3cfe4e15edfee98100d2 MD5 | raw file
  1. (function () {
  2. var STORAGE_KEY = 'weather.cities';
  3. var server = {
  4. getWeather: function (zip) {
  5. return $.getJSON('/Weather/GetWeather?zip=' + zip);
  6. }
  7. };
  8. var WeatherApp = Backbone.Model.extend({
  9. defaults: {
  10. 'unit': 'F'
  11. },
  12. initialize: function () {
  13. this.cities = new CityCollection();
  14. if(Modernizr.localstorage && localStorage[STORAGE_KEY]) {
  15. _.each(localStorage[STORAGE_KEY].split(','), function(z) {
  16. this.addCity(z);
  17. }, this);
  18. }
  19. else {
  20. this.addCity(98052);
  21. this.addCity(10001);
  22. this.addCity(75201);
  23. this.addCity(94121);
  24. }
  25. // bind to collection changes after adding the starting cities
  26. this.cities.bind('add remove', this.saveCities, this);
  27. },
  28. saveCities: function () {
  29. var data = this.cities.map(function(c) {
  30. return c.get('zip')
  31. }).join();
  32. localStorage[STORAGE_KEY] = data;
  33. },
  34. addCity: function (zip) {
  35. var city = new City({ 'app': this, 'zip': zip });
  36. this.cities.add(city);
  37. city.refresh();
  38. },
  39. getCities: function () {
  40. return this.cities;
  41. },
  42. refresh: function () {
  43. this.cities.each(function (c) {
  44. c.refresh();
  45. });
  46. },
  47. changeUnit: function () {
  48. var u = this.get('unit');
  49. if (u === 'F')
  50. u = 'C';
  51. else
  52. u = 'F';
  53. this.set({ 'unit': u });
  54. },
  55. getUnit: function () {
  56. return this.get('unit');
  57. }
  58. });
  59. var WeatherView = Backbone.View.extend({
  60. events: {
  61. 'click #unitCheckbox': 'changeUnit',
  62. 'click #refreshLink': 'refreshAll',
  63. 'submit form': 'addCity'
  64. },
  65. initialize: function () {
  66. this.template = _.template($('#weatherTemplate').html());
  67. this.model.bind('change', this.render, this);
  68. this.model.getCities().bind('all', this.focus, this);
  69. },
  70. focus: function () {
  71. $(this.el).find('#zipTextbox').focus();
  72. },
  73. changeUnit: function () {
  74. this.model.changeUnit();
  75. },
  76. refreshAll: function (evt) {
  77. evt.preventDefault();
  78. this.model.refresh();
  79. },
  80. addCity: function (evt) {
  81. evt.preventDefault();
  82. var $text = $('#zipTextbox');
  83. var zip = $text.val();
  84. if (zip) {
  85. this.model.addCity($text.val());
  86. $text.val('');
  87. }
  88. $text.focus();
  89. },
  90. render: function () {
  91. var self = this;
  92. //load the main UI
  93. $(this.el).html(this.template(this.model.toJSON()));
  94. $('#unitCheckbox').lightSwitch({
  95. switchImg: '/Content/lib/lightswitch/switch-unit.png',
  96. switchImgCover: '/Content/lib/lightswitch/switchplate.png',
  97. });
  98. // load the cities list
  99. var citiesView = new CityCollectionView({ collection: this.model.getCities() });
  100. $('#citiesDiv').html(citiesView.render().el);
  101. this.focus();
  102. return this;
  103. }
  104. });
  105. var City = Backbone.Model.extend({
  106. defaults: {
  107. 'name': '???',
  108. 'temperature': '???',
  109. 'state': '???',
  110. 'url': '???'
  111. },
  112. initialize: function () {
  113. this.app = this.get('app');
  114. this.state = 'init';
  115. this.farenheit = '???';
  116. this.celsius = '???';
  117. },
  118. invoke: function (event) {
  119. this.state = event;
  120. this.trigger(event);
  121. },
  122. getState: function () {
  123. return this.state;
  124. },
  125. getViewData: function () {
  126. var json = this.toJSON();
  127. json.unit = this.app.getUnit();
  128. json.temperature = this.app.getUnit() === 'F' ? this.farenheit : this.celsius;
  129. return json;
  130. },
  131. refresh: function () {
  132. this.invoke('loading');
  133. var self = this;
  134. var promise = server.getWeather(this.get('zip'));
  135. promise.done(function (data) {
  136. if (data.success) {
  137. self.farenheit = data.temperature;
  138. self.celsius = Math.round((data.temperature - 32) / 1.8);
  139. self.set({
  140. 'name': data.city,
  141. 'state': data.state,
  142. 'url': data.url
  143. });
  144. self.invoke('update');
  145. }
  146. else {
  147. self.invoke('error');
  148. }
  149. });
  150. promise.fail(function (data) {
  151. self.invoke('error');
  152. });
  153. }
  154. });
  155. var CityView = Backbone.View.extend({
  156. className: 'city',
  157. events: {
  158. 'click .city-refresh': 'refresh',
  159. 'click .city-remove': 'remove'
  160. },
  161. initialize: function () {
  162. this.template = _.template($('#cityTemplate').html());
  163. this.loadingTemplate = _.template($('#cityLoadingTemplate').html());
  164. this.errorTemplate = _.template($('#cityErrorTemplate').html());
  165. this.model.bind('update loading error', this.render, this);
  166. },
  167. render: function () {
  168. var viewData = this.model.getViewData();
  169. switch (this.model.getState()) {
  170. case 'loading':
  171. this.$el.removeClass('city-error');
  172. this.$el.html(this.loadingTemplate(viewData));
  173. break;
  174. case 'error':
  175. this.$el.html(this.errorTemplate(viewData));
  176. this.$el.addClass('city-error');
  177. break;
  178. default:
  179. this.$el.removeClass('city-error');
  180. this.$el.html(this.template(viewData));
  181. break;
  182. }
  183. this.$el.data('zip', viewData.zip);
  184. return this;
  185. },
  186. remove: function () {
  187. this.model.destroy();
  188. },
  189. refresh: function () {
  190. this.model.refresh();
  191. }
  192. });
  193. var CityCollection = Backbone.Collection.extend({
  194. model: City
  195. });
  196. var CityCollectionView = Backbone.View.extend({
  197. tagName: 'ul',
  198. events: {
  199. 'sortupdate': 'updateOrder'
  200. },
  201. initialize: function () {
  202. this.collection.bind('add destroy', this.render, this);
  203. },
  204. updateOrder: function () {
  205. var self = this;
  206. var sortedModels = [];
  207. this.$el.find('.city').each(function(index, city) {
  208. var cityModel = self.collection.where({ 'zip': $(city).data('zip') })[0];
  209. sortedModels.push(cityModel);
  210. });
  211. self.collection.reset(sortedModels);
  212. },
  213. render: function () {
  214. var self = this;
  215. self.$el.empty();
  216. this.collection.forEach(function (c) {
  217. var cityView = new CityView({ model: c });
  218. var $li = $('<li>').html(cityView.render().el);
  219. self.$el.append($li);
  220. });
  221. if(this.collection.length > 0) {
  222. self.$el.sortable();
  223. }
  224. return this;
  225. }
  226. });
  227. $(function () {
  228. var appView = new WeatherView({ model: new WeatherApp() });
  229. appView.setElement($('#appDiv'));
  230. appView.render();
  231. });
  232. })();