PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main-bb.js

https://bitbucket.org/yashdoshi89/rjs-compile-test
JavaScript | 328 lines | 130 code | 28 blank | 170 comment | 5 complexity | a93aefc51dc7d50d3bd47a49fca7ee95 MD5 | raw file
  1. define([
  2. 'config!',
  3. '$', 'underscore', 'backbone',
  4. 'lib/browsing',
  5. 'models/sitecollection', 'views/sitelistview',
  6. 'models/websearchmodel', 'views/websearchview',
  7. 'lib/bridge',
  8. 'views/widgetview',
  9. 'models/socialmodel', 'views/socialview',
  10. 'views/searchinputview',
  11. 'lib/decorateboot',
  12. 'xmessage'
  13. ],
  14. function (
  15. config,
  16. $, util, Backbone,
  17. browsing,
  18. SiteCollection, SiteListView,
  19. WebSearchModel, WebSearchView,
  20. bridge,
  21. WidgetView,
  22. SocialModel, SocialView,
  23. SearchInputView,
  24. decorateBoot,
  25. xmessage
  26. ) {
  27. var global = window || {};
  28. // App
  29. // -----------------------------------------------------------------------
  30. // Define an overall AppView that handles:
  31. //
  32. // * Updating the header/footer
  33. // * Binding events to elements that don't change across views.
  34. var superproto = WidgetView.prototype;
  35. var AppView = WidgetView.extend({
  36. el: $('#main-page'),
  37. // Use $.delegate to bind event handlers to elements inside
  38. // this element "live" -- in other words, if an element is brought
  39. // in with AJAX, the handler will attach as soon as the element exists.
  40. events: {
  41. 'click #header a': 'onlinkclick',
  42. 'click .menu-item': 'togglemenu',
  43. 'click #config-menu .menu-item': 'onconfigbuttonclick'
  44. },
  45. initialize: function (options) {
  46. options = options || {};
  47. superproto.initialize.call(this, options);
  48. },
  49. // Define handler to intercept link clicks and treat as router navigation
  50. onlinkclick: function(e) {
  51. e.preventDefault();
  52. e.stopPropagation();
  53. // use the link href to get the route path
  54. // pathname has a '/' prefix, so strip that off
  55. var path = e.target.pathname;
  56. bridge.navigate(path, true);
  57. },
  58. togglemenu: function (e) {
  59. var $toggle = $(e.currentTarget),
  60. $menu = $toggle.next().filter('.submenu'); // zepto's next() doesn't accept a selector
  61. // console.log("togglemenu with: ", e.currentTarget, $menu);
  62. if ($menu.length < 1) {
  63. // no submenu to toggle
  64. $toggle.closest(".submenu").hide();
  65. return;
  66. }
  67. if ($menu.css('display') !== 'none') {
  68. $menu.hide();
  69. }
  70. else {
  71. $menu.show();
  72. }
  73. e.preventDefault();
  74. e.stopPropagation();
  75. },
  76. onconfigbuttonclick: function(e){
  77. var btn = e.currentTarget,
  78. action = btn.getAttribute("data-action");
  79. switch(action){
  80. case "wipe":
  81. global.location = config.applicationRoot + "account/wipe";
  82. break;
  83. case "logout":
  84. $.ajax({
  85. url: config.apiRoot + "logout",
  86. type: "POST",
  87. async: false,
  88. dataType: "json",
  89. success: function(data, status, xhr) {
  90. // console.log("logout success");
  91. location.href = config.applicationRoot;
  92. },
  93. error: function(aXhr, aStatus, aErrorThrown) {
  94. console.warn("logout error: ", aErrorThrown);
  95. }
  96. });
  97. break;
  98. default:
  99. console.log("unknown config action: " + action);
  100. }
  101. // stop click handling here. return earlier to allow the event to bubble
  102. e.preventDefault();
  103. e.stopPropagation();
  104. },
  105. render: function () {
  106. // Add username to username area.
  107. this.$('.username').text(this.model.get('username'));
  108. return this;
  109. }
  110. });
  111. // Backbone's router and controllers are both bundled into this single
  112. // construct. `routes` registers routes, ties them to events and calls the
  113. // corresponding controller method. The corresponding controller is called
  114. // using the router's `this` context. This makes the router a good thing to
  115. // use as an app reference object.
  116. //
  117. // Given this situation, controllers are pretty thin, and mostly just handle
  118. // gluing together AppView and any associated models.
  119. var AppRouter = Backbone.Router.extend({
  120. initialize: function () {
  121. console.log("AppRouter initialize, with config: ", config);
  122. // The auth! plugin populates config with user data
  123. // Create a model for convenient/consistent acess to that
  124. var modelWithUserData = config.user = new Backbone.Model({
  125. csrf_token: config.csrf_token,
  126. username: config.username
  127. });
  128. var appView = new AppView({
  129. // App and state data should be stored on this model.
  130. model: modelWithUserData
  131. });
  132. appView.render();
  133. this.appView = appView;
  134. // Set up the search input control
  135. console.log("creating search view");
  136. // SearchInputView is attached to real DOM elements -- no need to
  137. // set as a widget.
  138. var searchView = new SearchInputView({
  139. el: $('#search-bar-container'),
  140. // Re-use main model rather than trying to keep separate models in
  141. // sync using events. If complexity grows, it might be worth splitting
  142. // these into separate models and syncing with events.
  143. model: modelWithUserData
  144. });
  145. }
  146. });
  147. // Initialize app router.
  148. var app = global.app = new AppRouter();
  149. // Configure routes. Route controllers are called every time the route is
  150. // matched. To handle items that should only be run once per controller, we
  151. // use a handy decorator that will run the first function given only once.
  152. // Main (Home) Controller.
  153. app.route('main', 'main', decorateBoot(
  154. // Run a boot-up once.
  155. function () {
  156. console.log('Booting Main Controller');
  157. // Set up site list with a new collection (default is top sites).
  158. var sites = new SiteListView({
  159. collection: new SiteCollection()
  160. });
  161. return {
  162. sites: sites
  163. };
  164. },
  165. function (booted) {
  166. var sites = booted.sites;
  167. this.appView.widgets({ '#content': sites });
  168. sites.collection.fetch({ diff: true });
  169. }
  170. ));
  171. // Search Controller.
  172. app.route('search/*query', 'search', decorateBoot(
  173. // Run a boot-up once.
  174. function (query) {
  175. console.log('Booting Search Controller with query:', query);
  176. // Create a new view for the main content area.
  177. var mainView = new WidgetView({
  178. html: '<div class="sites"></div><div class="search"></div>'
  179. });
  180. // Register sites widget.
  181. var sites = new SiteListView({
  182. collection: new SiteCollection({}, {
  183. tokens: { path: 'search' },
  184. query: { limit: 12 }
  185. })
  186. });
  187. // set up the search control
  188. var webSearchResults = new WebSearchView({
  189. model: new WebSearchModel()
  190. });
  191. var appViewModel = this.appView.model;
  192. // Bind to the webSearchResults widget's search:change` event.
  193. // When the search is changed via the view, update the search records.
  194. webSearchResults.bind('search:change', function(query){
  195. console.log("search:change event from the search widget: ", query);
  196. // keep the app bridge in sync
  197. if('search' in query){
  198. // Update the webSearchView's model data with query info.
  199. this.model.set(query, { silent: true });
  200. // only if the query changes do we need to update the
  201. // history/location
  202. appViewModel.set(query);
  203. }
  204. });
  205. // Register for the visit* events which are fired from the bridge (via the browsing module)
  206. // when a site visit occurs
  207. browsing.bind('registervisit', function(visitData){
  208. console.log("registervisit from the browsing module: ", visitData);
  209. });
  210. // Set widgets on mainView.
  211. mainView.widgets({
  212. '.sites': sites,
  213. '.search': webSearchResults
  214. });
  215. return {
  216. mainView: mainView
  217. };
  218. },
  219. function (booted, query) {
  220. // handling search route.
  221. global.currentController = booted;
  222. var mainView = booted.mainView,
  223. sites = mainView.widget('.sites'),
  224. webSearchResults = mainView.widget('.search'),
  225. params = {};
  226. this.appView.widgets({ '#content': booted.mainView });
  227. // parse out the query - it can be something like twitter/term1/term2 or just 'term'
  228. var terms = query.split('/'),
  229. // a master list of search providers we support, with name: prefix.
  230. // define in config maybe?
  231. providers = config.searchProviders;
  232. if(2 >= terms.length && terms[0] in providers) {
  233. // change search provider
  234. webSearchResults.model.set({
  235. 'provider': terms.shift() // pull the provider out of the search terms
  236. });
  237. }
  238. // api search
  239. var url = sites.collection.url(null, { q: terms.join(' ') });
  240. console.log("search controller, query: ", url);
  241. sites.fetch({ diff: true });
  242. // sync the search widget
  243. var searchUrl = webSearchResults.model.set({ query: terms.join(' ') });
  244. // web (bing/twitter) search
  245. webSearchResults.model.fetch();
  246. }
  247. ));
  248. // social controller
  249. app.route('social', 'social', decorateBoot(
  250. function () {
  251. console.log('Booting Social Controller');
  252. var socialModel = new SocialModel(),
  253. mainView = new SocialView({
  254. model: socialModel
  255. });
  256. return {
  257. socialModel: socialModel,
  258. mainView: mainView
  259. };
  260. },
  261. function (booted) {
  262. this.appView.widgets({ '#content': booted.mainView });
  263. // Hit the JSON API, create the various models and collections for this
  264. // view and store them in the SocialModel instance.
  265. booted.socialModel.fetch();
  266. }
  267. ));
  268. // Set a "static" reference to the router instance on bridge.
  269. // Used by bridge.navigate (a facade for Router.prototype.navigate).
  270. bridge.setActiveRouter(app);
  271. // Now that all of our routes are configured, start router listener.
  272. Backbone.history.start({pushState: true});
  273. // Export a limited API to the global space. To be consumed by native app.
  274. global.PANCAKE = bridge;
  275. // notify the 'top' window we're loaded
  276. xmessage.sendMessage("top", "ready", [{
  277. source: global.name, type: "ready"
  278. }], function (result) {});
  279. // Return app object for reference
  280. return app;
  281. });