GitHub PullRequestReviewCommentEvent at 2014-05-23 10:50:51
Repository: gaia
Actor: steveck-chung
Payload: {"comment":{"url":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/comments/12994098","id":12994098,"diff_hunk":"@@ -0,0 +1,314 @@\n+/* global\n+      Promise,\n+      Utils\n+*/\n+\n+/* exported Navigation */\n+\n+'use strict';\n+\n+(function(window) {\n+\n+// This function is used as a rejection handler, to swallow errors and log them\n+function catchError(e) {\n+  if (e) {\n+    console.error(\n+      'Navigation.toPanel: got an exception: (%s) %s',\n+      e, e.stack && e.stack.replace(/\\n/g, '|')\n+    );\n+  } else {\n+    console.log('Navigation.toPanel: got a rejected promise');\n+  }\n+}\n+\n+var currentPanel;\n+var queuedPanel;\n+\n+function nextQueuedPanel() {\n+  if (queuedPanel) {\n+    var next = queuedPanel;\n+    queuedPanel = null;\n+    Navigation.toPanel(next.panel, next.args)\n+      .then(next.defer.resolve, next.defer.reject);\n+  }\n+}\n+\n+var Navigation = window.Navigation = {\n+  panelObjects: window,\n+\n+  defaultPanel: 'thread-list',\n+\n+  panels: {\n+    'thread': {\n+      behaviour: 'ThreadUI',\n+      wrapperPosition: 'left'\n+    },\n+    'thread-list': {\n+      behaviour: 'ThreadListUI',\n+      wrapperPosition: 'right'\n+    },\n+    'composer': {\n+      behaviour: 'ThreadUI',\n+      wrapperPosition: 'left'\n+    },\n+    'group-view': {\n+      behaviour: 'GroupView',\n+      wrapperPosition: 'left'\n+    },\n+    'report-view': {\n+      behaviour: 'ReportView',\n+      wrapperPosition: 'left'\n+    }\n+  },\n+\n+  init: function n_init() {\n+    this.mainWrapper = document.getElementById('main-wrapper');\n+    this.transitioning = false;\n+\n+    return this.toPanelFromHash();\n+  },\n+\n+  /**\n+   * Returns a boolean.\n+   *\n+   * Called with a first argument that is not an object, it returns whether the\n+   * current panel is this first argument.\n+   *\n+   * Called with 2 arguments, the first one is not an object, the second one\n+   * must be an object. It returns whether the current panel is the first\n+   * argument, and for each property of the second argument, whether its value\n+   * is equal to the value for the current panel's arguments' same property.\n+   *\n+   * Called with 1 argument that is an object, it must have 2 properties panel\n+   * and args, which have the same meaning as the 2-argument call.\n+   */\n+  isCurrentPanel: function n_isCurrentPanel(panel, args) {\n+    if (!currentPanel || !panel) {\n+      return false;\n+    }\n+\n+    if (typeof panel === 'object') {\n+      args = panel.args;\n+      panel = panel.panel;\n+    }\n+\n+    if (panel !== currentPanel.panel) {\n+      return false;\n+    }\n+\n+    if (!args) {\n+      return true;\n+    }\n+\n+    var currentArgs = currentPanel.args || {};\n+\n+    for (var arg in args) {\n+      if (args[arg] !== currentArgs[arg]) {\n+        return false;\n+      }\n+    }\n+\n+    return true;\n+  },\n+\n+  /*\n+   * Returns the currentPanel object, with 2\n+   * properties: panel, args.\n+   */\n+  getCurrentPanel: function n_getCurrentPanel() {\n+    return currentPanel;\n+  },\n+\n+  /**\n+   * Lifecycle methods are called in this order:\n+   * - previousPanel.beforeLeave\n+   * - nextPanel.beforeEnter\n+   * - previousPanel.afterLeave\n+   * - nextPanel.afterEnter\n+   *\n+   * The panels are slid between beforeEnter and afterLeave.\n+   *\n+   * Therefore it is expected that:\n+   * - beforeLeave does not change any state but merely checks whether the\n+   *   transition can take place\n+   * - beforeEnter checks whether the transition can take place and make any\n+   *   visual change that should be made before the transition\n+   * - afterLeave cleans up the panel, reclaim memory\n+   * - afterEnter does left-over actions\n+   *\n+   * beforeLeave and beforeEnter can :\n+   * - throw or return a rejected Promise to stop the transition.\n+   * - finish normally or return a resolved Promise to continue the transition\n+   *\n+   * However, afterLeave and afterEnter should only finish normally or return a\n+   * resolved Promise. Otherwise, the errors will be logged but the transition\n+   * will finish.\n+   *\n+   * toPanel itself returns a Promise that will be resolved if the transition\n+   * happened and rejected otherwise.\n+   */\n+  toPanel: function n_toPanel(panel, args) {\n+    if (!(panel in this.panels)) {\n+      return Promise.reject(new Error('Panel ' + panel + ' is unknown.'));\n+    }\n+\n+    if (this.transitioning) {\n+      queuedPanel = {\n+        panel: panel,\n+        args: args\n+      };\n+\n+      return new Promise(function(resolve, reject) {\n+        queuedPanel.defer = {\n+          resolve: resolve,\n+          reject: reject\n+        };\n+      });\n+    }\n+\n+    // this checks both panel and args\n+    if (this.isCurrentPanel(panel, args)) {\n+      return Promise.resolve();\n+    }\n+\n+    var transitionArgs = args || {};\n+\n+    this.transitioning = true;\n+\n+    document.activeElement.blur();\n+\n+    transitionArgs.meta = {\n+      next: {\n+        panel: panel,\n+        args: args\n+      },\n+      prev: currentPanel\n+    };\n+\n+    var nextPanelInfo = this.panels[panel];\n+    var nextPanelObject = this.panelObjects[nextPanelInfo.behaviour];\n+\n+    if (!nextPanelObject) {\n+      var error = new Error(\n+        'Navigation.toPanel: no behaviour found for panel ' + panel\n+      );\n+      return Promise.reject(error);\n+    }\n+\n+    var currentPanelObject;\n+    if (currentPanel) {\n+      var currentPanelInfo = this.panels[currentPanel.panel];\n+      currentPanelObject = this.panelObjects[currentPanelInfo.behaviour];\n+    }\n+\n+    var promise = Promise.resolve();\n+\n+    // beforeLeave and beforeEnter can return a rejected promise to prevent\n+    // sliding. An exception is never expected though.\n+    if (currentPanelObject && currentPanelObject.beforeLeave) {\n+      promise = promise.then(\n+        currentPanelObject.beforeLeave.bind(currentPanelObject, transitionArgs)\n+      );\n+    }\n+\n+    if (nextPanelObject.beforeEnter) {\n+      promise = promise.then(\n+        nextPanelObject.beforeEnter.bind(nextPanelObject, transitionArgs)\n+      );\n+    }\n+\n+    // sliding\n+    promise = promise.then(\n+      this.slide.bind(this, nextPanelInfo.wrapperPosition)\n+    ).then(function changePanel() {\n+      currentPanel = {\n+        panel: panel,\n+        args: args\n+      };\n+    });\n+\n+    // afterLeave and afterEnter should not trigger errors\n+    promise = promise.then(function() {\n+      var promise = Promise.resolve();\n+\n+      if (currentPanelObject && currentPanelObject.afterLeave) {\n+        promise = promise.then(\n+          currentPanelObject.afterLeave.bind(currentPanelObject, transitionArgs)\n+        ).catch(catchError);\n+      }\n+\n+      if (nextPanelObject.afterEnter) {\n+        promise = promise.then(\n+          nextPanelObject.afterEnter.bind(nextPanelObject, transitionArgs)\n+        ).catch(catchError);\n+      }\n+\n+      return promise;\n+    });\n+\n+    promise = promise.then(\n+      function resolved() {\n+        this.transitioning = false;\n+      }.bind(this),\n+      function rejected(e) {\n+        catchError(e);\n+        this.transitioning = false;\n+        return Promise.reject(new Error('Error while transitioning'));\n+      }.bind(this)\n+    );\n+\n+    promise.then(nextQueuedPanel, nextQueuedPanel);\n+\n+    return promise;\n+  },\n+\n+  getPanelName: function n_getPanelName() {\n+    var hash = window.location.hash;\n+    if (hash.length && hash.startsWith('#')) {\n+      hash = hash.slice(1);\n+    }\n+\n+    var index;\n+    if ((index = hash.indexOf('&')) !== -1) {\n+      hash = hash.slice(0, index);\n+    }\n+\n+    return hash;\n+  },\n+\n+  toPanelFromHash: function n_toPanelFromHash() {\n+    var panelName = this.getPanelName() || this.defaultPanel;\n+    return this.toPanel(panelName, Utils.params(window.location.hash));\n+  },\n+\n+  slide: function n_slide(position) {\n+    var wrapper = this.mainWrapper;\n+\n+    // If no sliding is necessary, schedule the callback to be invoked as soon","path":"apps/sms/js/navigation.js","position":287,"original_position":287,"commit_id":"f0044450a735fd642fca8c7ff3bb6774cf90b52c","original_commit_id":"f0044450a735fd642fca8c7ff3bb6774cf90b52c","user":{"login":"steveck-chung","id":1704452,"avatar_url":"https://avatars.githubusercontent.com/u/1704452?","gravatar_id":"0e719389c6f6e17e5693819fc9a5722a","url":"https://api.github.com/users/steveck-chung","html_url":"https://github.com/steveck-chung","followers_url":"https://api.github.com/users/steveck-chung/followers","following_url":"https://api.github.com/users/steveck-chung/following{/other_user}","gists_url":"https://api.github.com/users/steveck-chung/gists{/gist_id}","starred_url":"https://api.github.com/users/steveck-chung/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/steveck-chung/subscriptions","organizations_url":"https://api.github.com/users/steveck-chung/orgs","repos_url":"https://api.github.com/users/steveck-chung/repos","events_url":"https://api.github.com/users/steveck-chung/events{/privacy}","received_events_url":"https://api.github.com/users/steveck-chung/received_events","type":"User","site_admin":false},"body":"nit: Maybe ```If the position of wrapper remain unchanged after sliding,```?","created_at":"2014-05-23T10:50:51Z","updated_at":"2014-05-23T10:50:51Z","html_url":"https://github.com/mozilla-b2g/gaia/pull/16377#discussion_r12994098","pull_request_url":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/16377","_links":{"self":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/comments/12994098"},"html":{"href":"https://github.com/mozilla-b2g/gaia/pull/16377#discussion_r12994098"},"pull_request":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/16377"}}}}