diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.html b/polygerrit-ui/app/elements/core/gr-router/gr-router.html
new file mode 100644
index 0000000000..2971ed27c5
--- /dev/null
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
new file mode 100644
index 0000000000..12fd31aece
--- /dev/null
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -0,0 +1,102 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+(function() {
+ 'use strict';
+
+ // Polymer makes `app` intrinsically defined on the window by virtue of the
+ // custom element having the id "app", but it is made explicit here.
+ var app = document.querySelector('#app');
+ var restAPI = document.createElement('gr-rest-api-interface');
+
+ window.addEventListener('WebComponentsReady', function() {
+ // Middleware
+ page(function(ctx, next) {
+ document.body.scrollTop = 0;
+ next();
+ });
+
+ function loadUser(ctx, next) {
+ restAPI.getLoggedIn().then(function() {
+ next();
+ })
+ }
+
+ // Routes.
+ page('/', loadUser, function(data) {
+ // For backward compatibility with GWT links.
+ if (data.hash) {
+ page.redirect(data.hash);
+ return;
+ }
+ restAPI.getLoggedIn().then(function(loggedIn) {
+ if (loggedIn) {
+ page.redirect('/dashboard/self');
+ } else {
+ page.redirect('/q/status:open');
+ }
+ });
+ });
+
+ page('/dashboard/(.*)', loadUser, function(data) {
+ restAPI.getLoggedIn().then(function(loggedIn) {
+ if (loggedIn) {
+ data.params.view = 'gr-dashboard-view';
+ app.params = data.params;
+ } else {
+ page.redirect('/login/' + encodeURIComponent(data.canonicalPath));
+ }
+ });
+ });
+
+ function queryHandler(data) {
+ data.params.view = 'gr-change-list-view';
+ app.params = data.params;
+ }
+
+ page('/q/:query,:offset', queryHandler);
+ page('/q/:query', queryHandler);
+
+ page(/^\/(\d+)\/?/, function(ctx) {
+ page.redirect('/c/' + ctx.params[0]);
+ });
+
+ page('/c/:changeNum/:patchNum?', function(data) {
+ data.params.view = 'gr-change-view';
+ app.params = data.params;
+ });
+
+ page(/^\/c\/(\d+)\/((\d+)(\.\.(\d+))?)\/(.+)/, function(ctx) {
+ var params = {
+ changeNum: ctx.params[0],
+ basePatchNum: ctx.params[2],
+ patchNum: ctx.params[4],
+ path: ctx.params[5],
+ view: 'gr-diff-view',
+ };
+ // Don't allow diffing the same patch number against itself because WHY?
+ if (params.basePatchNum == params.patchNum) {
+ page.redirect('/c/' + params.changeNum + '/' + params.patchNum + '/' +
+ params.path);
+ return;
+ }
+ if (!params.patchNum) {
+ params.patchNum = params.basePatchNum;
+ delete(params.basePatchNum);
+ }
+ app.params = params;
+ });
+
+ page.start();
+ });
+})();
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index b1c084e88d..33314a7094 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -20,6 +20,7 @@ limitations under the License.
+
@@ -29,8 +30,6 @@ limitations under the License.
-
-
diff --git a/polygerrit-ui/app/scripts/app.js b/polygerrit-ui/app/scripts/app.js
deleted file mode 100644
index 1922311944..0000000000
--- a/polygerrit-ui/app/scripts/app.js
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-'use strict';
-
-// Polymer makes `app` intrinsically defined on the window by virtue of the
-// custom element having the id "app", but it is made explicit here.
-var app = document.querySelector('#app');
-
-window.addEventListener('WebComponentsReady', function() {
- // Middleware
- page(function(ctx, next) {
- document.body.scrollTop = 0;
- next();
- });
-
- function loadUser(ctx, next) {
- app.accountReady.then(function() {
- next();
- });
- }
-
- // Routes.
- page('/', loadUser, function(data) {
- // For backward compatibility with GWT links.
- if (data.hash) {
- page.redirect(data.hash);
- return;
- }
- if (app.loggedIn) {
- page.redirect('/dashboard/self');
- } else {
- page.redirect('/q/status:open');
- }
- });
-
- page('/dashboard/(.*)', loadUser, function(data) {
- if (app.loggedIn) {
- data.params.view = 'gr-dashboard-view';
- app.params = data.params;
- } else {
- page.redirect('/login/' + encodeURIComponent(data.canonicalPath));
- }
- });
-
- function queryHandler(data) {
- data.params.view = 'gr-change-list-view';
- app.params = data.params;
- }
-
- page('/q/:query,:offset', queryHandler);
- page('/q/:query', queryHandler);
-
- page(/^\/(\d+)\/?/, function(ctx) {
- page.redirect('/c/' + ctx.params[0]);
- });
-
- page('/c/:changeNum/:patchNum?', function(data) {
- data.params.view = 'gr-change-view';
- app.params = data.params;
- });
-
- page(/^\/c\/(\d+)\/((\d+)(\.\.(\d+))?)\/(.+)/, function(ctx) {
- var params = {
- changeNum: ctx.params[0],
- basePatchNum: ctx.params[2],
- patchNum: ctx.params[4],
- path: ctx.params[5],
- view: 'gr-diff-view',
- };
- // Don't allow diffing the same patch number against itself because WHY?
- if (params.basePatchNum == params.patchNum) {
- page.redirect('/c/' + params.changeNum + '/' + params.patchNum + '/' +
- params.path);
- return;
- }
- if (!params.patchNum) {
- params.patchNum = params.basePatchNum;
- delete(params.basePatchNum);
- }
- app.params = params;
- });
-
- page.start();
-});