client/router: introduce own router

I'm tired of page.js lack of documentation around finer quirks, and
being forced to read its crap code. Refactored into classes, removed
unused cruft.
This commit is contained in:
rr- 2016-06-12 20:11:43 +02:00
parent 4295e1c827
commit 76882b59ef
19 changed files with 415 additions and 94 deletions

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const api = require('../api.js'); const api = require('../api.js');
const events = require('../events.js'); const events = require('../events.js');
const topNavController = require('../controllers/top_nav_controller.js'); const topNavController = require('../controllers/top_nav_controller.js');
@ -14,13 +14,20 @@ class AuthController {
} }
registerRoutes() { registerRoutes() {
page(/\/password-reset\/([^:]+):([^:]+)$/, router.enter(
/\/password-reset\/([^:]+):([^:]+)$/,
(ctx, next) => { (ctx, next) => {
this._passwordResetFinishRoute(ctx.params[0], ctx.params[1]); this._passwordResetFinishRoute(ctx.params[0], ctx.params[1]);
}); });
page('/password-reset', (ctx, next) => { this._passwordResetRoute(); }); router.enter(
page('/login', (ctx, next) => { this._loginRoute(); }); '/password-reset',
page('/logout', (ctx, next) => { this._logoutRoute(); }); (ctx, next) => { this._passwordResetRoute(); });
router.enter(
'/login',
(ctx, next) => { this._loginRoute(); });
router.enter(
'/logout',
(ctx, next) => { this._logoutRoute(); });
} }
_loginRoute() { _loginRoute() {
@ -33,7 +40,7 @@ class AuthController {
api.login(name, password, doRemember) api.login(name, password, doRemember)
.then(() => { .then(() => {
resolve(); resolve();
page('/'); router.show('/');
events.notify(events.Success, 'Logged in'); events.notify(events.Success, 'Logged in');
}, errorMessage => { }, errorMessage => {
reject(errorMessage); reject(errorMessage);
@ -46,7 +53,7 @@ class AuthController {
_logoutRoute() { _logoutRoute() {
api.forget(); api.forget();
api.logout(); api.logout();
page('/'); router.show('/');
events.notify(events.Success, 'Logged out'); events.notify(events.Success, 'Logged out');
} }
@ -68,10 +75,10 @@ class AuthController {
}, response => { }, response => {
return Promise.reject(response.description); return Promise.reject(response.description);
}).then(() => { }).then(() => {
page('/'); router.show('/');
events.notify(events.Success, 'New password: ' + password); events.notify(events.Success, 'New password: ' + password);
}, errorMessage => { }, errorMessage => {
page('/'); router.show('/');
events.notify(events.Error, errorMessage); events.notify(events.Error, errorMessage);
}); });
} }

View file

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const api = require('../api.js'); const api = require('../api.js');
const page = require('page'); const router = require('../router.js');
const misc = require('../util/misc.js'); const misc = require('../util/misc.js');
const topNavController = require('../controllers/top_nav_controller.js'); const topNavController = require('../controllers/top_nav_controller.js');
const pageController = require('../controllers/page_controller.js'); const pageController = require('../controllers/page_controller.js');
@ -10,7 +10,7 @@ const EmptyView = require('../views/empty_view.js');
class CommentsController { class CommentsController {
registerRoutes() { registerRoutes() {
page('/comments/:query?', router.enter('/comments/:query?',
(ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); },
(ctx, next) => { this._listCommentsRoute(ctx); }); (ctx, next) => { this._listCommentsRoute(ctx); });
this._commentsPageView = new CommentsPageView(); this._commentsPageView = new CommentsPageView();

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const topNavController = require('../controllers/top_nav_controller.js'); const topNavController = require('../controllers/top_nav_controller.js');
const HelpView = require('../views/help_view.js'); const HelpView = require('../views/help_view.js');
@ -10,11 +10,13 @@ class HelpController {
} }
registerRoutes() { registerRoutes() {
page('/help', () => { this._showHelpRoute(); }); router.enter(
page( '/help',
(ctx, next) => { this._showHelpRoute(); });
router.enter(
'/help/:section', '/help/:section',
(ctx, next) => { this._showHelpRoute(ctx.params.section); }); (ctx, next) => { this._showHelpRoute(ctx.params.section); });
page( router.enter(
'/help/:section/:subsection', '/help/:section/:subsection',
(ctx, next) => { (ctx, next) => {
this._showHelpRoute(ctx.params.section, ctx.params.subsection); this._showHelpRoute(ctx.params.section, ctx.params.subsection);

View file

@ -1,11 +1,13 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const topNavController = require('../controllers/top_nav_controller.js'); const topNavController = require('../controllers/top_nav_controller.js');
class HistoryController { class HistoryController {
registerRoutes() { registerRoutes() {
page('/history', (ctx, next) => { this._listHistoryRoute(); }); router.enter(
'/history',
(ctx, next) => { this._listHistoryRoute(); });
} }
_listHistoryRoute() { _listHistoryRoute() {

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const api = require('../api.js'); const api = require('../api.js');
const events = require('../events.js'); const events = require('../events.js');
const topNavController = require('../controllers/top_nav_controller.js'); const topNavController = require('../controllers/top_nav_controller.js');
@ -14,8 +14,12 @@ class HomeController {
} }
registerRoutes() { registerRoutes() {
page('/', (ctx, next) => { this._indexRoute(); }); router.enter(
page('*', (ctx, next) => { this._notFoundRoute(ctx); }); '/',
(ctx, next) => { this._indexRoute(); });
router.enter(
'*',
(ctx, next) => { this._notFoundRoute(ctx); });
} }
_indexRoute() { _indexRoute() {

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const api = require('../api.js'); const api = require('../api.js');
const settings = require('../settings.js'); const settings = require('../settings.js');
const events = require('../events.js'); const events = require('../events.js');
@ -20,14 +20,17 @@ class PostsController {
} }
registerRoutes() { registerRoutes() {
page('/upload', (ctx, next) => { this._uploadPostsRoute(); }); router.enter(
page('/posts/:query?', '/upload',
(ctx, next) => { this._uploadPostsRoute(); });
router.enter(
'/posts/:query?',
(ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); },
(ctx, next) => { this._listPostsRoute(ctx); }); (ctx, next) => { this._listPostsRoute(ctx); });
page( router.enter(
'/post/:id', '/post/:id',
(ctx, next) => { this._showPostRoute(ctx.params.id, false); }); (ctx, next) => { this._showPostRoute(ctx.params.id, false); });
page( router.enter(
'/post/:id/edit', '/post/:id/edit',
(ctx, next) => { this._showPostRoute(ctx.params.id, true); }); (ctx, next) => { this._showPostRoute(ctx.params.id, true); });
this._emptyView = new EmptyView(); this._emptyView = new EmptyView();

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const settings = require('../settings.js'); const settings = require('../settings.js');
const topNavController = require('../controllers/top_nav_controller.js'); const topNavController = require('../controllers/top_nav_controller.js');
const SettingsView = require('../views/settings_view.js'); const SettingsView = require('../views/settings_view.js');
@ -11,7 +11,7 @@ class SettingsController {
} }
registerRoutes() { registerRoutes() {
page('/settings', (ctx, next) => { this._settingsRoute(); }); router.enter('/settings', (ctx, next) => { this._settingsRoute(); });
} }
_settingsRoute() { _settingsRoute() {

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const api = require('../api.js'); const api = require('../api.js');
const tags = require('../tags.js'); const tags = require('../tags.js');
const events = require('../events.js'); const events = require('../events.js');
@ -23,20 +23,22 @@ class TagsController {
} }
registerRoutes() { registerRoutes() {
page('/tag-categories', () => { this._tagCategoriesRoute(); }); router.enter(
page( '/tag-categories',
(ctx, next) => { this._tagCategoriesRoute(ctx, next); });
router.enter(
'/tag/:name', '/tag/:name',
(ctx, next) => { this._loadTagRoute(ctx, next); }, (ctx, next) => { this._loadTagRoute(ctx, next); },
(ctx, next) => { this._showTagRoute(ctx, next); }); (ctx, next) => { this._showTagRoute(ctx, next); });
page( router.enter(
'/tag/:name/merge', '/tag/:name/merge',
(ctx, next) => { this._loadTagRoute(ctx, next); }, (ctx, next) => { this._loadTagRoute(ctx, next); },
(ctx, next) => { this._mergeTagRoute(ctx, next); }); (ctx, next) => { this._mergeTagRoute(ctx, next); });
page( router.enter(
'/tag/:name/delete', '/tag/:name/delete',
(ctx, next) => { this._loadTagRoute(ctx, next); }, (ctx, next) => { this._loadTagRoute(ctx, next); },
(ctx, next) => { this._deleteTagRoute(ctx, next); }); (ctx, next) => { this._deleteTagRoute(ctx, next); });
page( router.enter(
'/tags/:query?', '/tags/:query?',
(ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); },
(ctx, next) => { this._listTagsRoute(ctx, next); }); (ctx, next) => { this._listTagsRoute(ctx, next); });
@ -136,7 +138,7 @@ class TagsController {
_saveTag(tag, input) { _saveTag(tag, input) {
return api.put('/tag/' + tag.names[0], input).then(response => { return api.put('/tag/' + tag.names[0], input).then(response => {
if (input.names && input.names[0] !== tag.names[0]) { if (input.names && input.names[0] !== tag.names[0]) {
page('/tag/' + input.names[0]); router.show('/tag/' + input.names[0]);
} }
events.notify(events.Success, 'Tag saved.'); events.notify(events.Success, 'Tag saved.');
return Promise.resolve(); return Promise.resolve();
@ -151,7 +153,7 @@ class TagsController {
'/tag-merge/', '/tag-merge/',
{remove: tag.names[0], mergeTo: targetTagName} {remove: tag.names[0], mergeTo: targetTagName}
).then(response => { ).then(response => {
page('/tag/' + targetTagName + '/merge'); router.show('/tag/' + targetTagName + '/merge');
events.notify(events.Success, 'Tag merged.'); events.notify(events.Success, 'Tag merged.');
return Promise.resolve(); return Promise.resolve();
}, response => { }, response => {
@ -162,7 +164,7 @@ class TagsController {
_deleteTag(tag) { _deleteTag(tag) {
return api.delete('/tag/' + tag.names[0]).then(response => { return api.delete('/tag/' + tag.names[0]).then(response => {
page('/tags/'); router.show('/tags/');
events.notify(events.Success, 'Tag deleted.'); events.notify(events.Success, 'Tag deleted.');
return Promise.resolve(); return Promise.resolve();
}, response => { }, response => {

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const api = require('../api.js'); const api = require('../api.js');
const config = require('../config.js'); const config = require('../config.js');
const events = require('../events.js'); const events = require('../events.js');
@ -34,28 +34,31 @@ class UsersController {
} }
registerRoutes() { registerRoutes() {
page('/register', () => { this._createUserRoute(); }); router.enter(
page( '/register',
(ctx, next) => { this._createUserRoute(ctx, next); });
router.enter(
'/users/:query?', '/users/:query?',
(ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); },
(ctx, next) => { this._listUsersRoute(ctx, next); }); (ctx, next) => { this._listUsersRoute(ctx, next); });
page( router.enter(
'/user/:name', '/user/:name',
(ctx, next) => { this._loadUserRoute(ctx, next); }, (ctx, next) => { this._loadUserRoute(ctx, next); },
(ctx, next) => { this._showUserRoute(ctx, next); }); (ctx, next) => { this._showUserRoute(ctx, next); });
page( router.enter(
'/user/:name/edit', '/user/:name/edit',
(ctx, next) => { this._loadUserRoute(ctx, next); }, (ctx, next) => { this._loadUserRoute(ctx, next); },
(ctx, next) => { this._editUserRoute(ctx, next); }); (ctx, next) => { this._editUserRoute(ctx, next); });
page( router.enter(
'/user/:name/delete', '/user/:name/delete',
(ctx, next) => { this._loadUserRoute(ctx, next); }, (ctx, next) => { this._loadUserRoute(ctx, next); },
(ctx, next) => { this._deleteUserRoute(ctx, next); }); (ctx, next) => { this._deleteUserRoute(ctx, next); });
page.exit(/\/users\/.*/, (ctx, next) => { router.exit(
/\/users\/.*/, (ctx, next) => {
pageController.stop(); pageController.stop();
next(); next();
}); });
page.exit(/\/user\/.*/, (ctx, next) => { router.exit(/\/user\/.*/, (ctx, next) => {
this._cachedUser = null; this._cachedUser = null;
next(); next();
}); });
@ -81,7 +84,7 @@ class UsersController {
}); });
} }
_createUserRoute() { _createUserRoute(ctx, next) {
topNavController.activate('register'); topNavController.activate('register');
this._registrationView.render({ this._registrationView.render({
register: (...args) => { register: (...args) => {
@ -135,7 +138,7 @@ class UsersController {
return Promise.reject(response.description); return Promise.reject(response.description);
}).then(() => { }).then(() => {
resolve(); resolve();
page('/'); router.show('/');
events.notify(events.Success, 'Welcome aboard!'); events.notify(events.Success, 'Welcome aboard!');
}, errorMessage => { }, errorMessage => {
reject(); reject();
@ -184,7 +187,7 @@ class UsersController {
}).then(() => { }).then(() => {
resolve(); resolve();
if (data.name && data.name !== user.name) { if (data.name && data.name !== user.name) {
page('/user/' + data.name + '/edit'); router.show('/user/' + data.name + '/edit');
} }
events.notify(events.Success, 'Settings updated.'); events.notify(events.Success, 'Settings updated.');
}, errorMessage => { }, errorMessage => {
@ -203,9 +206,9 @@ class UsersController {
api.logout(); api.logout();
} }
if (api.hasPrivilege('users:list')) { if (api.hasPrivilege('users:list')) {
page('/users'); router.show('/users');
} else { } else {
page('/'); router.show('/');
} }
events.notify(events.Success, 'Account deleted.'); events.notify(events.Success, 'Account deleted.');
return Promise.resolve(); return Promise.resolve();

View file

@ -3,29 +3,34 @@
require('./util/polyfill.js'); require('./util/polyfill.js');
const misc = require('./util/misc.js'); const misc = require('./util/misc.js');
const page = require('page'); const router = require('./router.js');
const origPushState = page.Context.prototype.pushState;
page.Context.prototype.pushState = function() { const origPushState = router.Context.prototype.pushState;
router.Context.prototype.pushState = function() {
window.scrollTo(0, 0); window.scrollTo(0, 0);
origPushState.call(this); origPushState.call(this);
}; };
page.cancel = function(ctx) { router.cancel = function(ctx) {
prevContext = ctx; prevContext = ctx;
ctx.pushState(); ctx.pushState();
}; };
page.exit((ctx, next) => { router.exit(
/.*/,
(ctx, next) => {
views.unlistenToMessages(); views.unlistenToMessages();
if (misc.confirmPageExit()) { if (misc.confirmPageExit()) {
next(); next();
} else { } else {
page.cancel(ctx); router.cancel(ctx);
} }
}); });
const mousetrap = require('mousetrap'); const mousetrap = require('mousetrap');
page(/.*/, (ctx, next) => { router.enter(
/.*/,
(ctx, next) => {
mousetrap.reset(); mousetrap.reset();
next(); next();
}); });
@ -40,6 +45,7 @@ controllers.push(require('./controllers/history_controller.js'));
controllers.push(require('./controllers/tags_controller.js')); controllers.push(require('./controllers/tags_controller.js'));
controllers.push(require('./controllers/settings_controller.js')); controllers.push(require('./controllers/settings_controller.js'));
// home defines 404 routes, need to be registered as last
controllers.push(require('./controllers/home_controller.js')); controllers.push(require('./controllers/home_controller.js'));
const tags = require('./tags.js'); const tags = require('./tags.js');
@ -52,13 +58,13 @@ for (let controller of controllers) {
const api = require('./api.js'); const api = require('./api.js');
Promise.all([tags.refreshExport(), api.loginFromCookies()]) Promise.all([tags.refreshExport(), api.loginFromCookies()])
.then(() => { .then(() => {
page(); router.start();
}).catch(errorMessage => { }).catch(errorMessage => {
if (window.location.href.indexOf('login') !== -1) { if (window.location.href.indexOf('login') !== -1) {
api.forget(); api.forget();
page(); router.start();
} else { } else {
page('/'); router.start('/');
events.notify( events.notify(
events.Error, events.Error,
'An error happened while trying to log you in: ' + 'An error happened while trying to log you in: ' +

293
client/js/router.js Normal file
View file

@ -0,0 +1,293 @@
'use strict';
// modified page.js by visionmedia
// - removed unused crap
// - refactored to classes
const pathToRegexp = require('path-to-regexp');
const clickEvent = document.ontouchstart ? 'touchstart' : 'click';
let location = window.history.location || window.location;
const base = '';
let prevContext = null;
function _decodeURLEncodedURIComponent(val) {
if (typeof val !== 'string') {
return val;
}
return decodeURIComponent(val.replace(/\+/g, ' '));
}
function _isSameOrigin(href) {
let origin = location.protocol + '//' + location.hostname;
if (location.port) {
origin += ':' + location.port;
}
return href && href.indexOf(origin) === 0;
}
class Context {
constructor(path, state) {
if (path[0] === '/' && path.indexOf(base) !== 0) {
path = base + path;
}
this.canonicalPath = path;
this.path = path.replace(base, '') || '/';
this.title = document.title;
this.state = state || {};
this.state.path = path;
this.params = {};
}
pushState() {
history.pushState(this.state, this.title, this.canonicalPath);
}
save() {
history.replaceState(this.state, this.title, this.canonicalPath);
}
};
class Route {
constructor(path, options) {
options = options || {};
this.path = (path === '*') ? '(.*)' : path;
this.method = 'GET';
this.regexp = pathToRegexp(this.path, this.keys = [], options);
}
middleware(fn) {
return (ctx, next) => {
if (this.match(ctx.path, ctx.params)) {
return fn(ctx, next);
}
next();
};
}
match(path, params) {
const keys = this.keys;
const qsIndex = path.indexOf('?');
const pathname = ~qsIndex ? path.slice(0, qsIndex) : path;
const m = this.regexp.exec(decodeURIComponent(pathname));
if (!m) {
return false;
}
for (let i = 1, len = m.length; i < len; ++i) {
const key = keys[i - 1];
const val = _decodeURLEncodedURIComponent(m[i]);
if (val !== undefined || !(hasOwnProperty.call(params, key.name))) {
params[key.name] = val;
}
}
return true;
}
};
class Router {
constructor() {
this._callbacks = [];
this._exits = [];
this._current = '';
}
enter(path) {
const route = new Route(path);
for (let i = 1; i < arguments.length; ++i) {
this._callbacks.push(route.middleware(arguments[i]));
}
}
exit(path, fn) {
const route = new Route(path);
for (let i = 1; i < arguments.length; ++i) {
this._exits.push(route.middleware(arguments[i]));
}
}
start() {
if (this._running) {
return;
}
this._running = true;
this._onPopState = _onPopState(this);
this._onClick = _onClick(this);
window.addEventListener('popstate', this._onPopState, false);
document.addEventListener(clickEvent, this._onClick, false);
const url = location.pathname + location.search + location.hash;
this.replace(url, null, true);
}
stop() {
if (!this._running) {
return;
}
this._current = '';
this._running = false;
document.removeEventListener(clickEvent, this._onClick, false);
window.removeEventListener('popstate', this._onPopState, false);
}
show(path, state, push) {
const ctx = new Context(path, state);
this._current = ctx.path;
this.dispatch(ctx);
if (ctx.handled !== false && push !== false) {
ctx.pushState();
}
return ctx;
}
replace(path, state, dispatch) {
var ctx = new Context(path, state);
this._current = ctx.path;
ctx.save();
if (dispatch) {
this.dispatch(ctx);
}
return ctx;
}
dispatch(ctx) {
const prev = prevContext;
let i = 0;
let j = 0;
prevContext = ctx;
const nextExit = () => {
const fn = this._exits[j++];
if (!fn) {
return nextEnter();
}
fn(prev, nextExit);
};
const nextEnter = () => {
const fn = this._callbacks[i++];
if (ctx.path !== this._current) {
ctx.handled = false;
return;
}
if (!fn) {
return this._unhandled(ctx);
}
fn(ctx, nextEnter);
};
if (prev) {
nextExit();
} else {
nextEnter();
}
}
_unhandled(ctx) {
if (ctx.handled) {
return;
}
let current = location.pathname + location.search;
if (current === ctx.canonicalPath) {
return;
}
router.stop();
ctx.handled = false;
location.href = ctx.canonicalPath;
}
};
const _onPopState = router => {
let loaded = false;
if (document.readyState === 'complete') {
loaded = true;
} else {
window.addEventListener(
'load',
() => {
setTimeout(() => {
loaded = true;
}, 0);
});
}
return e => {
if (!loaded) {
return;
}
if (e.state) {
const path = e.state.path;
router.replace(path, e.state, true);
} else {
router.show(
location.pathname + location.hash,
undefined,
false);
}
};
};
const _onClick = router => {
return e => {
if (1 !== _which(e)) {
return;
}
if (e.metaKey || e.ctrlKey || e.shiftKey) {
return;
}
if (e.defaultPrevented) {
return;
}
let el = e.path ? e.path[0] : e.target;
while (el && el.nodeName !== 'A') {
el = el.parentNode;
}
if (!el || el.nodeName !== 'A') {
return;
}
if (el.hasAttribute('download') ||
el.getAttribute('rel') === 'external') {
return;
}
const link = el.getAttribute('href');
if (el.pathname === location.pathname && (el.hash || '#' === link)) {
return;
}
if (link && link.indexOf('mailto:') > -1) {
return;
}
if (el.target) {
return;
}
if (!_isSameOrigin(el.href)) {
return;
}
let path = el.pathname + el.search + (el.hash || '');
const orig = path;
if (path.indexOf(base) === 0) {
path = path.substr(base.length);
}
if (base && orig === path) {
return;
}
e.preventDefault();
router.show(orig);
};
};
function _which(e) {
e = e || window.event;
return e.which === null ? e.button : e.which;
}
Router.prototype.Context = Context;
Router.prototype.Route = Route;
module.exports = new Router();

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const events = require('../events.js'); const events = require('../events.js');
const views = require('../util/views.js'); const views = require('../util/views.js');
@ -55,10 +55,9 @@ class EndlessPageView {
} }
let topPageNumber = parseInt(topPageNode.getAttribute('data-page')); let topPageNumber = parseInt(topPageNode.getAttribute('data-page'));
if (topPageNumber !== this.currentPage) { if (topPageNumber !== this.currentPage) {
page.replace( router.replace(
_formatUrl(ctx.clientUrl, topPageNumber), _formatUrl(ctx.clientUrl, topPageNumber),
null, {},
false,
false); false);
this.currentPage = topPageNumber; this.currentPage = topPageNumber;
} }

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const config = require('../config.js'); const config = require('../config.js');
const misc = require('../util/misc.js'); const misc = require('../util/misc.js');
const views = require('../util/views.js'); const views = require('../util/views.js');
@ -32,7 +32,7 @@ class HomeView {
form.querySelector('input[name=all-posts') form.querySelector('input[name=all-posts')
.addEventListener('click', e => { .addEventListener('click', e => {
e.preventDefault(); e.preventDefault();
page('/posts/'); router.show('/posts/');
}); });
const searchTextInput = form.querySelector( const searchTextInput = form.querySelector(
@ -42,7 +42,7 @@ class HomeView {
e.preventDefault(); e.preventDefault();
const text = searchTextInput.value; const text = searchTextInput.value;
searchTextInput.blur(); searchTextInput.blur();
page('/posts/' + misc.formatSearchQuery({text: text})); router.show('/posts/' + misc.formatSearchQuery({text: text}));
}); });
} }

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const events = require('../events.js'); const events = require('../events.js');
const keyboard = require('../util/keyboard.js'); const keyboard = require('../util/keyboard.js');
const misc = require('../util/misc.js'); const misc = require('../util/misc.js');
@ -85,12 +85,12 @@ class ManualPageView {
keyboard.bind(['a', 'left'], () => { keyboard.bind(['a', 'left'], () => {
if (currentPage > 1) { if (currentPage > 1) {
page.show(_formatUrl(ctx.clientUrl, currentPage - 1)); router.show(_formatUrl(ctx.clientUrl, currentPage - 1));
} }
}); });
keyboard.bind(['d', 'right'], () => { keyboard.bind(['d', 'right'], () => {
if (currentPage < totalPages) { if (currentPage < totalPages) {
page.show(_formatUrl(ctx.clientUrl, currentPage + 1)); router.show(_formatUrl(ctx.clientUrl, currentPage + 1));
} }
}); });

View file

@ -1,9 +1,9 @@
'use strict'; 'use strict';
const api = require('../api.js'); const api = require('../api.js');
const router = require('../router.js');
const views = require('../util/views.js'); const views = require('../util/views.js');
const keyboard = require('../util/keyboard.js'); const keyboard = require('../util/keyboard.js');
const page = require('page');
const PostContentControl = require('../controls/post_content_control.js'); const PostContentControl = require('../controls/post_content_control.js');
const PostNotesOverlayControl const PostNotesOverlayControl
= require('../controls/post_notes_overlay_control.js'); = require('../controls/post_notes_overlay_control.js');
@ -60,19 +60,19 @@ class PostView {
keyboard.bind('e', () => { keyboard.bind('e', () => {
if (ctx.editMode) { if (ctx.editMode) {
page.show('/post/' + ctx.post.id); router.show('/post/' + ctx.post.id);
} else { } else {
page.show('/post/' + ctx.post.id + '/edit'); router.show('/post/' + ctx.post.id + '/edit');
} }
}); });
keyboard.bind(['a', 'left'], () => { keyboard.bind(['a', 'left'], () => {
if (ctx.nextPostId) { if (ctx.nextPostId) {
page.show('/post/' + ctx.nextPostId); router.show('/post/' + ctx.nextPostId);
} }
}); });
keyboard.bind(['d', 'right'], () => { keyboard.bind(['d', 'right'], () => {
if (ctx.prevPostId) { if (ctx.prevPostId) {
page.show('/post/' + ctx.prevPostId); router.show('/post/' + ctx.prevPostId);
} }
}); });
} }

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const settings = require('../settings.js'); const settings = require('../settings.js');
const keyboard = require('../util/keyboard.js'); const keyboard = require('../util/keyboard.js');
const misc = require('../util/misc.js'); const misc = require('../util/misc.js');
@ -56,14 +56,14 @@ class PostsHeaderView {
browsingSettings.listPosts[safety] browsingSettings.listPosts[safety]
= !browsingSettings.listPosts[safety]; = !browsingSettings.listPosts[safety];
settings.saveSettings(browsingSettings, true); settings.saveSettings(browsingSettings, true);
page(url.replace(/{page}/, 1)); router.show(url.replace(/{page}/, 1));
} }
_evtFormSubmit(e, searchTextInput) { _evtFormSubmit(e, searchTextInput) {
e.preventDefault(); e.preventDefault();
const text = searchTextInput.value; const text = searchTextInput.value;
searchTextInput.blur(); searchTextInput.blur();
page('/posts/' + misc.formatSearchQuery({text: text})); router.show('/posts/' + misc.formatSearchQuery({text: text}));
} }
} }

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const keyboard = require('../util/keyboard.js'); const keyboard = require('../util/keyboard.js');
const misc = require('../util/misc.js'); const misc = require('../util/misc.js');
const views = require('../util/views.js'); const views = require('../util/views.js');
@ -31,7 +31,7 @@ class TagsHeaderView {
e.preventDefault(); e.preventDefault();
const text = searchTextInput.value; const text = searchTextInput.value;
searchTextInput.blur(); searchTextInput.blur();
page('/tags/' + misc.formatSearchQuery({text: text})); router.show('/tags/' + misc.formatSearchQuery({text: text}));
}); });
views.showView(target, source); views.showView(target, source);

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const page = require('page'); const router = require('../router.js');
const keyboard = require('../util/keyboard.js'); const keyboard = require('../util/keyboard.js');
const misc = require('../util/misc.js'); const misc = require('../util/misc.js');
const views = require('../util/views.js'); const views = require('../util/views.js');
@ -25,7 +25,7 @@ class UsersHeaderView {
const searchTextInput = form.querySelector('[name=search-text]'); const searchTextInput = form.querySelector('[name=search-text]');
const text = searchTextInput.value; const text = searchTextInput.value;
searchTextInput.blur(); searchTextInput.blur();
page('/users/' + misc.formatSearchQuery({text: text})); router.show('/users/' + misc.formatSearchQuery({text: text}));
}); });
views.showView(target, source); views.showView(target, source);

View file

@ -22,7 +22,7 @@
"merge": "^1.2.0", "merge": "^1.2.0",
"mousetrap": "^1.5.3", "mousetrap": "^1.5.3",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"page": "^1.7.1", "path-to-regexp": "^1.5.1",
"stylus": "^0.54.2", "stylus": "^0.54.2",
"superagent": "^1.8.3", "superagent": "^1.8.3",
"uglify-js": "git://github.com/mishoo/UglifyJS2.git#harmony", "uglify-js": "git://github.com/mishoo/UglifyJS2.git#harmony",