PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/js/app.js

https://bitbucket.org/jkodumal/rmanalan.bitbucket.org
JavaScript | 396 lines | 350 code | 30 blank | 16 comment | 34 complexity | 45078789933520dfe22b3d0b1d424911 MD5 | raw file
  1. $(function() {
  2. rest = {};
  3. rest.services = [
  4. {
  5. "wadl": "bb-wadl.xml",
  6. "path": "https://api.bitbucket.org/1.0",
  7. "version": "1.0",
  8. "pluginCompleteKey": "jira",
  9. "pluginName": "rab",
  10. "pluginDescription": "some descr"
  11. }
  12. ];
  13. rest.jsonRpcs = [];
  14. rest.slugify = function(str) {
  15. return str.toLowerCase().replace(/[^-a-zA-Z0-9,&\s]+/ig, '-').replace(/\s/gi, "-").replace(/^-/, '').replace(/-$/, '');
  16. };
  17. var Service = Backbone.Model.extend({});
  18. var Services = Backbone.Collection.extend({
  19. model: Service,
  20. findByKey: function(key) {
  21. return services.find(function(s) {
  22. return s.get('pluginCompleteKey') === key;
  23. });
  24. }
  25. });
  26. var Resource = Backbone.Model.extend({});
  27. var Resources = Backbone.Collection.extend({
  28. model: Resource
  29. });
  30. var services = [];
  31. rest.services = rest.services.sort(function(x, y) {
  32. return (x.pluginName < y.pluginName) ? - 1 : 1;
  33. });
  34. $.each(rest.services, function() {
  35. this.pluginCompleteKey = rest.slugify(this.pluginCompleteKey);
  36. services.push(new Service(this));
  37. });
  38. services = new Services(services);
  39. var ResourceBody = Backbone.View.extend({
  40. template: $('#rab-resource-body'),
  41. el: $('#rab'),
  42. initialize: function() {
  43. this.render();
  44. // Size and position sidebar and main content properly
  45. appViewController.sizeBoxes();
  46. },
  47. render: function() {
  48. $(window).scrollTop(0);
  49. console.log(1, this.model.toJSON(),this.$el.html());
  50. this.$el.html(this.template.tmpl(this.model.toJSON()));
  51. }
  52. });
  53. var CurrentService = Backbone.View.extend({
  54. el: $('.rab-curr-service'),
  55. template: $('#rab-header-tmpl'),
  56. initialize: function(model) {
  57. this.model = model;
  58. var self = this;
  59. this.render();
  60. new ServiceSelector(model);
  61. this.getResources(this.model.get('wadl'));
  62. },
  63. events: {
  64. 'click .rab-name': 'toggleDD',
  65. 'click .menu-item a': 'navigate'
  66. },
  67. render: function(model) {
  68. model = model || this.model;
  69. this.$('.rab-curr-head').html(this.template.tmpl(model.attributes));
  70. },
  71. name: function() {
  72. return this.model.get('pluginCompleteKey');
  73. },
  74. getResources: function(wadlUrl) {
  75. var self = this;
  76. processWADL(wadlUrl).done(function(d) {
  77. self.model.set(d);
  78. new ResourceBody({
  79. model: self.model
  80. });
  81. rest.resources = d;
  82. });
  83. },
  84. toggleDD: function(e) {
  85. if (this.$('.rab-services-dd').hasClass('rab-open')) {
  86. // Close the dd
  87. this.$('.rab-services-dd').removeClass('rab-open');
  88. this.$('.rab-dd-button').removeClass('rab-dd-button-open');
  89. } else {
  90. // Open the dd
  91. this.$('.rab-services-dd').css('left',
  92. function() {
  93. var point = e.clientX;
  94. var left = e.clientX - ($(this).width() / 2);
  95. return left > 0 ? left : 0;
  96. }).addClass('rab-open');
  97. this.$('.rab-dd-button').addClass('rab-dd-button-open');
  98. var self = this;
  99. $('body').bind('click', function() {
  100. if ($('.rab-services-dd').hasClass('rab-open')) {
  101. self.toggleDD(e);
  102. }
  103. $('body').unbind('click');
  104. return false
  105. });
  106. }
  107. return false;
  108. },
  109. navigate: function(e) {
  110. var target = $(e.currentTarget);
  111. // Disabled for Bamboo
  112. console.log('before routing',$('body'))
  113. if ($('body').id !== 'jira' && $('body').id !== 'com-atlassian-confluence') {
  114. console.log('routing')
  115. appRouter.navigate(target.attr('href'));
  116. }
  117. this.toggleDD(e);
  118. this.switchService(target.data('id'));
  119. return false;
  120. },
  121. switchService: function(key) {
  122. if (!key) {
  123. this.model = services.first();
  124. } else {
  125. this.model = services.findByKey(key);
  126. }
  127. this.render(this.model);
  128. this.getResources(this.model.get('wadl'));
  129. }
  130. });
  131. var ServicesDDItem = Backbone.View.extend({
  132. template: $('#rab-menu-item'),
  133. initialize: function() {
  134. this.render();
  135. },
  136. render: function() {
  137. $('.rab-services-dd').append(this.template.tmpl(this.model.toJSON()));
  138. }
  139. });
  140. var ServiceSelector = Backbone.View.extend({
  141. el: $('.rab-service-selector'),
  142. initialize: function(model) {
  143. services.each(function(service) {
  144. new ServicesDDItem({
  145. model: service
  146. });
  147. });
  148. }
  149. });
  150. var BrowserView = Backbone.View.extend({
  151. initialize: function(model) {
  152. rest.currService = new CurrentService(model);
  153. }
  154. });
  155. // Main view controller. Initialized only once.
  156. var AppViewController = Backbone.View.extend({
  157. el: $(window),
  158. events: {
  159. 'submit .rab-endpoint': 'performCall',
  160. 'click .rab-clear': 'clearOutput',
  161. 'resize': 'sizeBoxes',
  162. 'click .rab-resources-sb a': 'scrollToResource',
  163. 'scroll': 'handleScroll',
  164. 'click .rab-add-custom-param': 'addCustomParam',
  165. 'click .rab-delete-custom-param': 'deleteCustomParam'
  166. },
  167. initialize:function() {
  168. // Stupid fucking hack to combat against fecru's weird
  169. // header positioning... lame.
  170. if ($('body > div.layoutCentredPane').length) {
  171. this.headerOffset = 0;
  172. } else {
  173. this.headerOffset = $('#header').height();
  174. }
  175. },
  176. addCustomParam: function(e) {
  177. var params = $(e.currentTarget).parent().parent();
  178. $('#rab-custom-param-tmpl').tmpl().insertBefore(params);
  179. return false;
  180. },
  181. deleteCustomParam: function(e) {
  182. $(e.currentTarget).parent().parent().remove();
  183. return false;
  184. },
  185. sizeBoxes: function() {
  186. var self = this;
  187. $('.rab-sidebar').height(function() {
  188. return self.$el.height() - 10;
  189. });
  190. this.origSidebarTop = $('.rab-sidebar').scrollTop();
  191. this.origSidebarOffsetTop = $('.rab-sidebar').offset().top;
  192. this.origSidebarWidth = $('.rab-sidebar').width();
  193. this.winHeight = this.$el.height();
  194. this.handleScroll();
  195. },
  196. handleScroll: function(w) {
  197. var currPosn, contentBottom, x = $('.rab-resources').position().left, top = this.$el.scrollTop(), elFromPoint = $(document.elementFromPoint(x, 5));
  198. // Highlight selected resource in sidebar as the main content
  199. // is scrolled.
  200. if (elFromPoint.hasClass('rab-resource')) {
  201. $('.rab-resource-sb a').removeClass('rab-resource-sb-active');
  202. $('#rab-nav-' + elFromPoint.data('id')).addClass('rab-resource-sb-active');
  203. }
  204. // Fix the sidebar as the main content container is scrolled allowing
  205. // for easy access to resources without it scrolling off the screen.
  206. currPosn = top + appViewController.winHeight;
  207. if (top > appViewController.origSidebarOffsetTop) {
  208. contentBottom = this.origSidebarOffsetTop + $('.rab-content').height();
  209. if (currPosn > contentBottom) {
  210. $('.rab-sidebar').css({
  211. top: contentBottom - currPosn
  212. });
  213. } else {
  214. $('.rab-sidebar').css({
  215. position: "fixed",
  216. top: 0,
  217. width: appViewController.origSidebarWidth
  218. });
  219. $('.rab-content').css({
  220. marginLeft: "20%"
  221. });
  222. }
  223. } else {
  224. $('.rab-sidebar').css({
  225. position: "static",
  226. width: "20%"
  227. });
  228. $('.rab-content').css({
  229. marginLeft: "0"
  230. });
  231. }
  232. },
  233. scrollToResource:function(e) {
  234. var self = $(e.currentTarget);
  235. $('.rab-resource-sb a').removeClass('rab-resource-sb-active');
  236. self.addClass('rab-resource-sb-active');
  237. $(window).scrollTop($(self.attr('href')).position().top + this.headerOffset);
  238. return false;
  239. },
  240. performCall: function(e) {
  241. var queryParams, jsonRpcParams, customParams, data, outputType,
  242. form = $(e.currentTarget),
  243. url = form.attr('action'),
  244. method = form.attr('method'),
  245. representation = form.find('select[name=representation]').val();
  246. $.each(form.find('.rab-param-style-template'), function() {
  247. var self = $(this), pat = new RegExp('\{' + self.attr('name') + '\:?(.*)\}', 'g');
  248. url = url.replace(pat, self.val());
  249. });
  250. queryParams = $.map(form.find('.rab-param-style-query'), function(e) {
  251. var self = $(e);
  252. if (self.val() !== '')
  253. return self.serialize();
  254. });
  255. jsonRpcParams = [].concat($.map(form.find('.rab-param-style-jsonRpc'), function(e) {
  256. return $(e).val();
  257. }));
  258. customParams = $.map(form.find('.rab-custom-params'), function(e) {
  259. var self = $(e), paramName = self.find('.rab-param-style-custom-name').val(), paramVal = self.find('.rab-param-style-custom-value').val();
  260. if (paramName && paramVal)
  261. return paramName + "=" + paramVal;
  262. });
  263. $.merge($.merge(queryParams, jsonRpcParams), customParams);
  264. if (queryParams.length > 0) {
  265. url += "?" + queryParams.join('&');
  266. }
  267. if (jsonRpcParams.length > 0) {
  268. data = JSON.stringify(jsonRpcParams);
  269. representation = 'application/json';
  270. } else if (method === "POST" || method === "PUT") {
  271. data = form.find('textarea').val();
  272. if (data.trim() === "") {
  273. data = "{}";
  274. }
  275. }
  276. if (representation === 'application/xml') {
  277. outputType = 'xml';
  278. } else {
  279. outputType = 'json';
  280. }
  281. $.ajax({
  282. url: url,
  283. type: method,
  284. data: data,
  285. contentType: representation,
  286. dataType: outputType,
  287. beforeSend: function() {
  288. form.find('.rab-throbber').removeClass('hidden');
  289. form.find('.rab-exec').attr('disabled', 'disabled');
  290. },
  291. complete: function() {
  292. form.find('.rab-throbber').addClass('hidden');
  293. form.find('.rab-exec').removeAttr('disabled');
  294. }
  295. }).done(
  296. function(d, msg, o) {
  297. var contentType, rsp = {};
  298. rsp.headers = o.getAllResponseHeaders();
  299. contentType = o.getResponseHeader('Content-Type');
  300. if (/^application\/xml/.test(contentType)) {
  301. rsp.body = o.responseText;
  302. } else {
  303. try {
  304. rsp.body = JSON.stringify(d, null, 2);
  305. } catch(e) {
  306. try {
  307. rsp.body = d.documentElement.innerHTML;
  308. } catch(e) {
  309. rsp.body = d;
  310. }
  311. }
  312. }
  313. if (rsp.body == null) rsp.body = "";
  314. rsp.call = method + " " + url + " (" + o.status + ")";
  315. form.next().html($('#rab-output-tmpl').tmpl(rsp));
  316. prettyPrint();
  317. }).fail(function(o, msg, descr) {
  318. var rsp = {};
  319. rsp.headers = o.getAllResponseHeaders();
  320. try {
  321. rsp.body = JSON.stringify(JSON.parse(o.responseText), null, 2);
  322. } catch(e) {
  323. rsp.body = o.responseText;
  324. }
  325. if (rsp.body == null) rsp.body = "";
  326. rsp.call = method + " " + url + " (" + o.status + ")";
  327. form.next().html($('#rab-output-tmpl').tmpl(rsp));
  328. prettyPrint();
  329. });
  330. return false;
  331. },
  332. clearOutput:function(e) {
  333. $(e.currentTarget).parent().next().empty();
  334. return false;
  335. }
  336. });
  337. var appViewController = new AppViewController();
  338. var AppRouter = Backbone.Router.extend({
  339. routes: {
  340. '/': 'home',
  341. '/:key': 'service',
  342. '*page': 'catchAll'
  343. },
  344. home: function() {
  345. new BrowserView(services.first());
  346. },
  347. service: function(key) {
  348. var svc = services.findByKey(key);
  349. if (svc) {
  350. new BrowserView(svc);
  351. } else {
  352. appRouter.navigate('/');
  353. }
  354. },
  355. catchAll: function() {
  356. this.navigate('/', true);
  357. }
  358. });
  359. var appRouter = new AppRouter();
  360. // Workaround to Bamboo's shitty DOMContentLoad bug
  361. // if ($('body#jira').length > 0 || $('body#com-atlassian-confluence').length > 0) {
  362. // Backbone.history.start();
  363. // } else {
  364. new BrowserView(services.first());
  365. // }
  366. });