PageRenderTime 70ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

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

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