PageRenderTime 70ms CodeModel.GetById 43ms RepoModel.GetById 0ms app.codeStats 0ms

/agora_site/static/js/agora/views/generic.js

https://bitbucket.org/rafacouto/agora-ciudadana-fork
JavaScript | 466 lines | 360 code | 80 blank | 26 comment | 40 complexity | 81c6e452de34383732d8392e1cd6184b MD5 | raw file
  1. (function() {
  2. var Agora = this.Agora,
  3. app = this.app;
  4. /*
  5. * Agora calendar widget scope
  6. */
  7. (function() {
  8. var ElectionModel = Backbone.Model.extend({});
  9. var ElectionsCollection = Backbone.Collection.extend({
  10. model: ElectionModel
  11. });
  12. Agora.CalendarWidgetView = Backbone.View.extend({
  13. el: "#agora-calendar",
  14. events: {
  15. "keyup .election-search-query": "onSearchChange"
  16. },
  17. initialize: function() {
  18. _.bindAll(this);
  19. this.template = _.template($("#template-election").html());
  20. this.collection = new ElectionsCollection();
  21. this.collection.on('reset', this.resetCollection);
  22. var ajax = new Ajax();
  23. ajax.on('success', this.initializeSuccess);
  24. ajax.get(this.$el.data('url'));
  25. // Debouncing
  26. this.onSearchChange = _.debounce(this.onSearchChange, 400);
  27. },
  28. initializeSuccess: function(xhr) {
  29. if (xhr.status === 200) {
  30. var data = JSON.parse(xhr.responseText);
  31. this.collection.reset(data.objects);
  32. }
  33. },
  34. onSearchChange: function(event) {
  35. var target = $(event.currentTarget);
  36. var data = {"q": target.val()};
  37. var ajax = new Ajax();
  38. ajax.on('success', this.initializeSuccess);
  39. ajax.get(this.$el.data('url'), data);
  40. console.log("onSearchChange: " + target.val());
  41. },
  42. resetCollection: function(collection) {
  43. this.$(".list-container").empty();
  44. var data = collection.groupBy(function(item) {
  45. var date = item.get('voting_extended_until_date') ||
  46. item.get('voting_ends_at_date') ||
  47. item.get('voting_starts_at_date');
  48. if (date) {
  49. return date.split("T")[0];
  50. } else {
  51. return null;
  52. }
  53. });
  54. _.each(_.pairs(data), function(item) {
  55. var key = item[0],
  56. val = item[1];
  57. var date = moment(key);
  58. var dom = this.template({"datetime":date.format("LL"), "items": val});
  59. this.$(".list-container").append(dom);
  60. }, this);
  61. if (collection.length === 0) {
  62. this.$(".list-container").append(this.$("#no-elections"));
  63. }
  64. }
  65. });
  66. }).call(this);
  67. /*
  68. * Agoras list widget scope.
  69. */
  70. (function() {
  71. var AgoraModel = Backbone.Model.extend({});
  72. var AgorasCollection = Backbone.Collection.extend({
  73. model: AgoraModel
  74. });
  75. Agora.AgoraWidgetListView = Backbone.View.extend({
  76. el: "#agora-list",
  77. initialize: function() {
  78. _.bindAll(this);
  79. this.agoraTemplate = _.template($("#template-agora").html());
  80. this.agorasCollection = new AgorasCollection();
  81. this.agorasCollection.on('reset', this.resetAgorasCollection);
  82. var ajax = new Ajax();
  83. ajax.on("success", this.initializeSuccess);
  84. ajax.get(this.$el.data('url'));
  85. },
  86. initializeSuccess: function(xhr) {
  87. if (xhr.status === 200) {
  88. var data = JSON.parse(xhr.responseText);
  89. this.agorasCollection.reset(data.objects);
  90. }
  91. },
  92. resetAgorasCollection: function(collection) {
  93. this.$(".last-agoras .list-container").empty();
  94. if (collection.length === 0) {
  95. var emptyItem = this.make('ul', {'id':'no-agoras'}, gettext('No agoras found'));
  96. this.$(".last-agoras .list-container").append(emptyItem);
  97. } else {
  98. collection.each(this.addAgoraItem);
  99. }
  100. },
  101. addAgoraItem: function(model) {
  102. var dom = this.agoraTemplate(model.toJSON());
  103. this.$(".last-agoras .list-container").append(dom);
  104. }
  105. });
  106. }).call(this);
  107. /**
  108. * Used for showing modal dialogs
  109. */
  110. (function() {
  111. Agora.ModalDialogView = Backbone.View.extend({
  112. el: "#modaldialogdiv",
  113. initialize: function() {
  114. _.bindAll(this);
  115. this.template = _.template($("#template-modal_dialog").html());
  116. this.delegateEvents();
  117. },
  118. populate: function(header, body, footer) {
  119. this.$el.html(this.template({'header': header,
  120. 'body': body,
  121. 'footer': footer}));
  122. this.delegateEvents();
  123. },
  124. modal: function(data) {
  125. this.$el.find("#modal_dialog").modal(data);
  126. },
  127. hide: function() {
  128. this.modal('hide');
  129. },
  130. show: function() {
  131. this.modal('show');
  132. },
  133. });
  134. }).call(this);
  135. /**
  136. * used to delegate your vote
  137. */
  138. Agora.delegateVoteHandler = function(e, self) {
  139. if (self.sendingData) {
  140. return;
  141. }
  142. var agora = $(e.target).data('agora');
  143. var delegate = $(e.target).data('delegate');
  144. var ballot = {
  145. 'action':'delegate_vote',
  146. 'user_id': delegate.id
  147. };
  148. var data = {"agora": agora, "delegate": delegate};
  149. app.confirmDelegateActionDialog = new Agora.ModalDialogView();
  150. var title = interpolate(gettext("Confirm delegation to %s in agora %s"),
  151. [delegate.full_name, agora.full_name]);
  152. var body = _.template($("#template-confirm_delegate_modal_dialog_body").html())(data);
  153. var footer = _.template($("#template-confirm_delegate_modal_dialog_footer").html())();
  154. app.confirmDelegateActionDialog.populate(title, body, footer);
  155. app.confirmDelegateActionDialog.show();
  156. self.sendingData = true;
  157. $("#confirm-delegate-action").click(function(e, self) {
  158. e.preventDefault();
  159. if ($("#confirm-delegate-action").hasClass("disabled")) {
  160. return false;
  161. }
  162. $("#confirm-delegate-action").addClass("disabled");
  163. var jqxhr = $.ajax("/api/v1/agora/" + agora.id + "/action/", {
  164. data: JSON.stringifyCompat(ballot),
  165. contentType : 'application/json',
  166. type: 'POST',
  167. })
  168. .done(function(e, self) {
  169. self.sendingData = false;
  170. $("#modal_dialog").modal('hide');
  171. return false;
  172. })
  173. .fail(function(e, self) {
  174. $("#confirm-delegate-action").removeClass("disabled");
  175. alert("Error casting the ballot, try again or report this problem");
  176. $("#modal_dialog").modal('hide');
  177. return false;
  178. });
  179. return false;
  180. });
  181. $("#deny-delegate-action").click(function(e, self) {
  182. $("#modal_dialog").modal('hide');
  183. return false;
  184. });
  185. self.sendingData = false;
  186. };
  187. /*
  188. * Generic view for all search pages.
  189. */
  190. (function() {
  191. var ItemModel = Backbone.Model.extend({});
  192. var ItemCollection = Backbone.Collection.extend({
  193. model: ItemModel
  194. });
  195. Agora.GenericListView = Backbone.View.extend({
  196. el: "#activity-list",
  197. events: {
  198. "click a.endless_more": "onMoreClicked"
  199. },
  200. setup: function() {
  201. this.url = this.$el.data('url');
  202. this.method = this.$el.data('method') || 'get';
  203. },
  204. setupTemplates: function() {
  205. if (this.templateEl !== undefined) {
  206. this.template = _.template($(this.templateEl).html());
  207. }
  208. },
  209. initialize: function() {
  210. _.bindAll(this);
  211. this.firstLoadSuccess = false;
  212. this.finished = false;
  213. this.collection = new ItemCollection();
  214. this.collection.on('reset', this.collectionReset);
  215. this.collection.on('add', this.addItem);
  216. this.endlessDom = this.$(".endless-container");
  217. this.endlessDom.find("div.endless_loading").hide();
  218. this.offset = 0;
  219. this.limit = 20;
  220. this.setup();
  221. this.setupTemplates();
  222. this.delegateEvents();
  223. this.requestObjects();
  224. $(window).scroll(this.infiniteScroll);
  225. },
  226. requestObjects: function() {
  227. if (!this.finished) {
  228. var ajax = new Ajax();
  229. ajax.on('success', this.requestSuccess);
  230. var params = _.extend({}, {limit:this.limit, offset: this.offset},
  231. this.params || {});
  232. this.offset += this.limit;
  233. if (this.method === 'get') {
  234. ajax.get(this.url, params);
  235. } else if (this.method === 'post') {
  236. ajax.post(this.url, params);
  237. }
  238. }
  239. },
  240. setEndlessFinishDom: function() {
  241. this.endlessDom.find("a.endless_more").replaceWith(gettext("<span>No more results</span>"));
  242. this.endlessDom.find("div.endless_loading").hide();
  243. },
  244. requestSuccess: function(xhr) {
  245. if (xhr.status === 200) {
  246. var data = JSON.parse(xhr.responseText);
  247. this.endlessDom.find("div.endless_loading").hide();
  248. if (data.objects.length === 0) {
  249. this.setEndlessFinishDom();
  250. this.finished = true;
  251. } else {
  252. var doc = $(document), win = $(window);
  253. if (!this.firstLoadSuccess) {
  254. this.firstLoadSuccess = true;
  255. this.collection.reset(data.objects);
  256. } else {
  257. this.$("a.endless_more").show();
  258. _.each(data.objects, function(item) {
  259. this.collection.add(item);
  260. }, this);
  261. }
  262. this.endlessDom.appendTo(this.$el);
  263. // if received less than the limit per page, it means
  264. // there are no more items
  265. if (data.objects.length < this.limit) {
  266. this.setEndlessFinishDom();
  267. this.finished = true;
  268. // if received the limit per page, but the doc is still
  269. // the same height as the window and scrollTop is 0,
  270. // it means the window admits more elements and more
  271. // elements can be fetch, so fetch those
  272. } else if (doc.height() == win.height() &&
  273. win.scrollTop() == 0) {
  274. this.onMoreClicked();
  275. this.$("a.endless_more").hide();
  276. this.endlessDom.find("div.endless_loading").show();
  277. }
  278. }
  279. }
  280. },
  281. collectionReset: function(collection) {
  282. this.$el.empty();
  283. collection.each(this.addItem);
  284. },
  285. renderItem: function(model) {
  286. if (this.template !== undefined) {
  287. return this.template(model.toJSON());
  288. } else {
  289. return "<div>REIMPLEMENT THIS</div>";
  290. }
  291. },
  292. addItem: function(model) {
  293. var html = this.renderItem(model);
  294. this.$el.append(html);
  295. },
  296. infiniteScroll: function() {
  297. var doc = $(document), win = $(window);
  298. var margin = this.$el.data('margin') || 300;
  299. if (!this.finished &&
  300. (doc.height() - win.height() - win.scrollTop()) <= margin)
  301. {
  302. this.onMoreClicked();
  303. this.$("a.endless_more").hide();
  304. this.endlessDom.find("div.endless_loading").show();
  305. }
  306. },
  307. onMoreClicked: function(event) {
  308. if (event) {
  309. event.preventDefault();
  310. }
  311. this.requestObjects();
  312. }
  313. });
  314. Agora.ActivityListView = Agora.GenericListView.extend({
  315. el: "#activity-list",
  316. setup: function() {
  317. this.url = this.$el.data('url');
  318. this.method = this.$el.data('method') || 'get';
  319. this.templates = {}
  320. },
  321. renderItem: function(model) {
  322. var json = model.toJSON();
  323. json.actor.initials = Agora.getUserInitials(json.actor);
  324. if (!this.templates[json.type_name]) {
  325. this.templates[json.type_name] = _.template(
  326. $('#template-action_' + json.type_name).html()
  327. || '<#template-action_' + json.type_name
  328. + ' not found>'
  329. );
  330. }
  331. return this.templates[json.type_name](json);
  332. }
  333. });
  334. Agora.getUserInitials = function(json) {
  335. if (json.full_name && json.full_name != json.username) {
  336. var initials = "";
  337. var words = $.trim(json.full_name).split(" ");
  338. _.each(words, function (word) {
  339. var trimmed = $.trim(word);
  340. if (trimmed.length > 0) {
  341. initials += word[0].toUpperCase();
  342. }
  343. });
  344. return initials;
  345. } else {
  346. return json.username[0].toUpperCase();
  347. }
  348. };
  349. /**
  350. * This view renders a dynamic action list view. Inherit it
  351. * overriding the model in the setup() function.
  352. */
  353. Agora.ActionListView = Backbone.View.extend({
  354. el: "#action_list",
  355. events: {
  356. 'click a.main-action': 'doMainAction',
  357. 'click a.action-link': 'doAction'
  358. },
  359. initialize: function() {
  360. _.bindAll(this);
  361. this.template = _.template($("#template-action_list").html());
  362. this.setup();
  363. this.render();
  364. return this.$el;
  365. },
  366. setup: function() {
  367. this.model = {};
  368. },
  369. render: function() {
  370. if (this.model) {
  371. this.$el.html(this.template(this.model));
  372. this.delegateEvents();
  373. }
  374. return this;
  375. },
  376. doAction: function(e) {
  377. e.preventDefault();
  378. console.log("doAction not implemented");
  379. },
  380. doMainAction: function(e) {
  381. e.preventDefault();
  382. console.log("doMainAction not implemented");
  383. }
  384. });
  385. }).call(this);
  386. }).call(this);