PageRenderTime 65ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/city_aware/templates/staff/edit_sponsors.html

https://github.com/hack4reno2011/Rock-Star-Scientists
HTML | 344 lines | 322 code | 22 blank | 0 comment | 0 complexity | f2632fe4463c5e136cbdaa2b60ba5fbd MD5 | raw file
  1. {% extends "foundation.html" %}
  2. {% load url from future %}
  3. {% block headers %}
  4. <style type="text/css">
  5. .editHolder {
  6. width:600px;
  7. }
  8. .label {
  9. width:600px;
  10. clear:both;
  11. }
  12. .options {
  13. float:right;
  14. }
  15. .inputBar {
  16. }
  17. .labelInput {
  18. width:400px;
  19. }
  20. #searchResults {
  21. width:300px;
  22. }
  23. </style>
  24. <script>
  25. var inputMenu = "<div id='barCell'><span class='inputBar'><label>Name:<input id='newName' type='text'></input></label>Venue:<input type='text' id='defaultVenue' placeholder='No default venue selected' readonly=true></input><input id='venuePK' type='hidden'></input><button id='removeVenue'>Remove Venue</button><button id='add'>Add</button></div><div id='searchArea'></span></div>";
  26. var sortMenu = "<button id='sortByName'>Sort by Name</button><button id='sortById'>Sort by ID</button>";
  27. var noIdItem = '<div class="label"><%- name %><div class="options"><button class="delete">delete</button></div></div>';
  28. var wIdItem = '<div class="label"><%- name %>(<%- venue %>)<div class="options"><button class="delete">delete</button></div></div>';
  29. var editTemp = '<div class="editHolder"><input class="labelInput" value="<%= name %>"></input><div class="options"><button class="delete">delete</button></div></div>';
  30. var viewSearchResult = '<span class="label"><%- name %></span>';
  31. var searchMenu = '<label>Find a venue:<input id="searchBox" type="text"></input></label>';
  32. var data = []
  33. $(function() {
  34. var Item = Backbone.Model.extend({
  35. defaults: {'name': "Unknown"},
  36. urlRoot: '/api/sponsors/',
  37. });
  38. var List = Backbone.Collection.extend({
  39. model: Item,
  40. url: '/api/sponsors/',
  41. parse: function(data) {
  42. return data.objects;
  43. },
  44. comparator: function(item) {
  45. return item.get('id');
  46. }
  47. });
  48. var Venue = Backbone.Model.extend({
  49. defaults: {'name': "Unknown Venue"},
  50. urlRoot: '/api/venues/',
  51. });
  52. var VenueView = Backbone.View.extend({
  53. tagName: 'li',
  54. events: {
  55. 'click span.label': 'selectVenue',
  56. },
  57. initialize: function() {
  58. _.bindAll(this, 'render', 'unrender', 'remove', 'selectVenue');
  59. this.model.bind('change', this.render);
  60. this.model.bind('remove', this.unrender);
  61. },
  62. render: function() {
  63. console.log("render venue");
  64. $(this.el).html(_.template(viewSearchResult, this.model.toJSON()));
  65. return this;
  66. },
  67. unrender: function() {
  68. $(this.el).remove();
  69. },
  70. selectVenue: function() {
  71. console.log("venue selected:", this.model.get('id'));
  72. $('#defaultVenue').val(this.model.get('name'));
  73. $('#venuePK').val(this.model.get('id'));
  74. },
  75. });
  76. var VenueList = Backbone.Collection.extend({
  77. model: Venue,
  78. url: '/api/venues/',
  79. parse: function(data) {
  80. return data.objects;
  81. },
  82. comparator: function(item) {
  83. return item.get('name');
  84. }
  85. });
  86. var SearchResults = Backbone.View.extend({
  87. tagName: 'div',
  88. className: 'searchArea',
  89. events: {
  90. },
  91. initialize: function() {
  92. _.bindAll(this, 'render', 'renderSearchResults', 'newSearch', 'appendVenue');
  93. //TODO fetch results starting with the characters
  94. this.collection = new VenueList();
  95. this.collection.bind('add', this.appendVenue);
  96. this.collection.bind('reset', this.renderSearchResults);
  97. this.render();
  98. this.newSearch();
  99. },
  100. render: function() {
  101. console.log("rendering search results");
  102. console.log(this.el);
  103. //$(this.el).append(_.template(searchMenu, {})).append("<ul id='searchResults'></ul>");
  104. $('#searchArea').append(_.template(searchMenu, {})).append("<ul id='searchResults'></ul>");
  105. $('#searchBox').keyup(this.newSearch);
  106. },
  107. renderSearchResults: function() {
  108. //$('#searchResults', this.el).empty();
  109. $('#searchResults').empty();
  110. // _.each?
  111. for (var i = 0; i < this.collection.models.length; i++) {
  112. this.appendVenue(this.collection.models[i]);
  113. }
  114. },
  115. newSearch: function() {
  116. //TODO grab the search term from the search
  117. //var searchTerm = "Pioneer Center";
  118. //TODO strip!
  119. var searchTerm = $('#searchBox').val();
  120. if (searchTerm) {
  121. console.log("searching for:", searchTerm);
  122. this.collection.fetch({data: {'name__istartswith': searchTerm}});
  123. } else {
  124. //empty the list
  125. this.collection.reset();
  126. }
  127. },
  128. appendVenue: function(item) {
  129. console.log("appending new venue:", item);
  130. var venueResult = new VenueView({
  131. model: item
  132. });
  133. //$('#searchResults', this.el).append(venueResult.render().el);
  134. $('#searchResults').append(venueResult.render().el);
  135. },
  136. newItem: function() {
  137. var newText = $('input', this.el).val();
  138. if (newText) {
  139. //TODO not empty?
  140. var randItem = new Item({'name': newText});
  141. randItem.save({}, {success: buildSuccessReponse(this.collection)});
  142. var newText = $('input', this.el).val("");
  143. }
  144. },
  145. });
  146. var ItemView = Backbone.View.extend({
  147. tagName: 'li',
  148. className: 'green',
  149. events: {
  150. 'click button.delete': 'remove',
  151. 'dblclick div.label': "editLabel",
  152. },
  153. initialize: function() {
  154. _.bindAll(this, 'render', 'unrender', 'remove', 'editLabel', 'saveLabel');
  155. this.model.bind('change', this.render);
  156. this.model.bind('remove', this.unrender);
  157. },
  158. render: function() {
  159. if (this.model.get('venue')) {
  160. $(this.el).html(_.template(wIdItem, this.model.toJSON()));
  161. } else {
  162. $(this.el).html(_.template(noIdItem, this.model.toJSON()));
  163. }
  164. return this;
  165. },
  166. editLabel: function() {
  167. //change the template to editing mode
  168. $(this.el).html(_.template(editTemp, this.model.toJSON()))
  169. //TODO should only save on change
  170. $('input.labelInput', this.el).focusout(this.saveLabel).change(this.saveLabel).bind("keypress", function(e) {if (e.keyCode == 13) {this.saveLabel};});
  171. },
  172. saveLabel: function() {
  173. //TODO confirm new text, delete if empty
  174. var newText = $('input.labelInput', this.el).val();
  175. this.model.set({'name': newText});
  176. this.model.save();
  177. //TODO rerender no matter what happened: avoid duplication with save call
  178. $(this.el).html(_.template(noIdItem, this.model.toJSON()));
  179. },
  180. unrender: function() {
  181. $(this.el).remove();
  182. },
  183. remove: function() {
  184. //this.model.destroy();
  185. //TODO no need for custom callbacks?
  186. console.log("preparing to destroy:", this.model);
  187. this.model.destroy({error: function(model, response) {
  188. console.log("DELETE error:", response);
  189. },
  190. success: function(model, response) {
  191. //apparently, reports success on 301 ?!?!
  192. console.log("DELETE success:", model, response);
  193. }
  194. });
  195. }
  196. });
  197. //TODO why global?
  198. var iList = (new List()).add(data);
  199. var AppView = Backbone.View.extend({
  200. el: $('#tableCell'),
  201. events: {
  202. 'click button#refresh': "refreshList",
  203. 'click button#add': "newItem",
  204. 'click button#removeVenue': "removeVenue",
  205. 'click button#sortByName': "sortByName",
  206. 'click button#sortById': "sortById",
  207. },
  208. initialize: function() {
  209. _.bindAll(this, 'render', 'addItem', 'appendItem', 'sortByName', 'renderList', 'sortById', 'newItem', 'refreshList', 'removeVenue');
  210. this.collection = iList.bind('add', this.appendItem);
  211. this.sortOrder = -1;
  212. this.render();
  213. this.collection = iList.bind('reset', this.renderList);
  214. this.collection.fetch(); //fires 'reset'
  215. //this.collection.fetch({add: true}); //otherwise list will 'reset'
  216. //this.collection.fetch({add: true, data: {offset: 50}}); //otherwise list will 'reset'
  217. //this.collection.sort(); //should fire 'reset'
  218. },
  219. render: function() {
  220. $(this.el).append(_.template(inputMenu, {})).append(_.template(sortMenu, {})).append("<ul id='sponsorList'></ul>");
  221. //TODO after rendering the search area, start up the search view
  222. this.renderList();
  223. var venueSearch = new SearchResults();
  224. },
  225. renderList: function() {
  226. $('ul#sponsorList', this.el).empty();
  227. // _.each?
  228. for (var i = 0; i < this.collection.models.length; i++) {
  229. this.appendItem(this.collection.models[i]);
  230. }
  231. },
  232. addItem: function() {
  233. this.collection.add(new Item({'name': "new bus stop"}));
  234. },
  235. appendItem: function(item) {
  236. var itemView = new ItemView({
  237. model: item
  238. });
  239. $('ul#sponsorList', this.el).append(itemView.render().el);
  240. },
  241. sortByName: function() {
  242. this.sortOrder = -this.sortOrder;
  243. this.collection.comparator = buildNameComparator(this.sortOrder);
  244. this.collection.sort();
  245. },
  246. sortById: function() {
  247. this.sortOrder = -this.sortOrder;
  248. this.collection.comparator = buildIdComparator(this.sortOrder);
  249. this.collection.sort();
  250. },
  251. newItem: function() {
  252. //TODO add optional venue key
  253. var newText = $('#newName', this.el).val();
  254. var newVenue = $('#venuePK', this.el).val();
  255. if (!newVenue) {
  256. newVenue = null;
  257. } else {
  258. //TODO in case of error set null? or reject addition
  259. newVenue = parseInt(newVenue, 10);
  260. }
  261. console.log("preparing to save sponsor:", newText, newVenue);
  262. if (newText) {
  263. //var newSponsor = new Item({'name': newText, 'venue': {'pk': newVenue}});
  264. if (newVenue == null) {
  265. var newSponsor = new Item({'name': newText, 'venue': null});
  266. console.log('saving:', newSponsor);
  267. newSponsor.save({}, {success: buildSuccessReponse(this.collection)});
  268. } else {
  269. var newSponsor = new Item({'name': newText, 'venue': "/api/venues/" + newVenue + "/"});
  270. console.log('saving:', newSponsor);
  271. newSponsor.save({}, {success: buildSuccessReponse(this.collection)});
  272. }
  273. var newText = $('#newName', this.el).val("");
  274. this.removeVenue();
  275. }
  276. },
  277. refreshList: function() {
  278. this.collection.fetch(); //fires 'reset'
  279. },
  280. removeVenue: function() {
  281. //remove the select default venue from the add sponsor list
  282. console.log("removing the default venue");
  283. $('#defaultVenue').val("");
  284. $('#venuePK').val("");
  285. }
  286. });
  287. function buildIdComparator(sortOrder) {
  288. return function(country) {
  289. return sortOrder * country.get('id');
  290. }
  291. }
  292. function buildNameComparator(sortOrder) {
  293. return function(item) {
  294. return _.map(item.get("name").toLowerCase().split(""), function(letter) {
  295. return String.fromCharCode(sortOrder * (letter.charCodeAt(0)));
  296. });;
  297. }
  298. }
  299. function buildSuccessReponse(collection) {
  300. return function(model, response) {
  301. collection.add(model);
  302. collection.sort();
  303. }
  304. }
  305. var app = new AppView();
  306. });
  307. </script>
  308. {% endblock %}
  309. {% block content %}
  310. <p><a href="{% url 'staff_home' %}">&lt&lt&lt Return to Staff Homepage</a></p>
  311. <h4>Add a sponsor:</h4>
  312. <div id="tableCell"></div>
  313. <div id="overlay" style="display:none">
  314. <div id="overlayPrompt">
  315. <span id="overlayQuestion"></span>
  316. <div id="overlayButtons">
  317. <button id="overlayYes" >Yes</button>
  318. <button id="overlayNo" >No</button>
  319. </div>
  320. </div>
  321. </div>
  322. {% endblock %}