diff --git a/client/html/post.tpl b/client/html/post.tpl index ecb4ba8..af98422 100644 --- a/client/html/post.tpl +++ b/client/html/post.tpl @@ -3,11 +3,7 @@ <nav class='buttons'> <article class='next-post'> <% if (ctx.nextPostId) { %> - <% if (ctx.searchQuery && ctx.searchQuery.text) { %> - <a href='/post/<%- encodeURIComponent(ctx.nextPostId) %>/text=<%- encodeURIComponent(ctx.searchQuery.text) %>'> - <% } else { %> - <a href='/post/<%- encodeURIComponent(ctx.nextPostId) %>'> - <% } %> + <a href='<%= ctx.getPostUrl(ctx.nextPostId, ctx.parameters) %>'> <% } else { %> <a class='inactive'> <% } %> @@ -17,11 +13,7 @@ </article> <article class='previous-post'> <% if (ctx.prevPostId) { %> - <% if (ctx.searchQuery && ctx.searchQuery.text) { %> - <a href='/post/<%- encodeURIComponent(ctx.prevPostId) %>/text=<%- encodeURIComponent(ctx.searchQuery.text) %>'> - <% } else { %> - <a href='/post/<%- encodeURIComponent(ctx.prevPostId) %>'> - <% } %> + <a href='<%= ctx.getPostUrl(ctx.prevPostId, ctx.parameters) %>'> <% } else { %> <a class='inactive'> <% } %> @@ -37,11 +29,7 @@ </a> <% } else { %> <% if (ctx.canEditPosts) { %> - <% if (ctx.searchQuery && ctx.searchQuery.text) { %> - <a href='/post/<%- encodeURIComponent(ctx.post.id) %>/edit/text=<%- encodeURIComponent(ctx.searchQuery.text) %>'> - <% } else { %> - <a href='/post/<%- encodeURIComponent(ctx.post.id) %>/edit'> - <% } %> + <a href='<%= ctx.getPostEditUrl(ctx.post.id, ctx.parameters) %>'> <% } else { %> <a class='inactive'> <% } %> diff --git a/client/html/post_readonly_sidebar.tpl b/client/html/post_readonly_sidebar.tpl index 5272731..351d93d 100644 --- a/client/html/post_readonly_sidebar.tpl +++ b/client/html/post_readonly_sidebar.tpl @@ -51,11 +51,7 @@ <ul><!-- --><% for (let post of ctx.post.relations) { %><!-- --><li><!-- - --><% if (ctx.searchQuery && ctx.searchQuery.text) { %><!-- - --><a href='/post/<%- encodeURIComponent(post.id) %>/text=<%- encodeURIComponent(ctx.searchQuery.text) %>'><!-- - --><% } else { %><!-- - --><a href='/post/<%- encodeURIComponent(post.id) %>'><!-- - --><% } %><!-- + --><a href='<%= ctx.getPostUrl(post.id, ctx.parameters) %>'><!-- --><%= ctx.makeThumbnail(post.thumbnailUrl) %><!-- --></a><!-- --></li><!-- @@ -77,7 +73,7 @@ --></a><!-- --><% } %><!-- --><% if (ctx.canListPosts) { %><!-- - --><a href='/posts/text=<%- encodeURIComponent(tag) %>' class='<%= ctx.makeCssName(ctx.getTagCategory(tag), 'tag') %>'><!-- + --><a href='/posts/query=<%- encodeURIComponent(tag) %>' class='<%= ctx.makeCssName(ctx.getTagCategory(tag), 'tag') %>'><!-- --><% } %><!-- --><%- tag %><!-- --><% if (ctx.canListPosts) { %><!-- diff --git a/client/html/posts_header.tpl b/client/html/posts_header.tpl index f92cff7..a1af737 100644 --- a/client/html/posts_header.tpl +++ b/client/html/posts_header.tpl @@ -1,6 +1,6 @@ <div class='post-list-header'> <form class='horizontal search'> - <%= ctx.makeTextInput({text: 'Search query', id: 'search-text', name: 'search-text', value: ctx.searchQuery.text}) %> + <%= ctx.makeTextInput({text: 'Search query', id: 'search-text', name: 'search-text', value: ctx.parameters.query}) %> <input class='mousetrap' type='submit' value='Search'/> <input data-safety=safe type='button' class='mousetrap safety safety-safe <%- ctx.settings.listPosts.safe ? '' : 'disabled' %>'/> <input data-safety=sketchy type='button' class='mousetrap safety safety-sketchy <%- ctx.settings.listPosts.sketchy ? '' : 'disabled' %>'/> @@ -9,12 +9,12 @@ </form> <% if (ctx.canMassTag) { %> <form class='masstag horizontal'> - <% if (ctx.searchQuery.tag) { %> + <% if (ctx.parameters.tag) { %> <span class='append'>Tagging with:</span> <% } else { %> <a class='mousetrap button append open-masstag' href='#'>Mass tag</a> <% } %> - <%= ctx.makeTextInput({name: 'masstag', value: ctx.searchQuery.tag}) %> + <%= ctx.makeTextInput({name: 'masstag', value: ctx.parameters.tag}) %> <input class='mousetrap start-tagging' type='submit' value='Start tagging'/> <a class='mousetrap button append stop-tagging' href='#'>Stop tagging</a> </form> diff --git a/client/html/posts_page.tpl b/client/html/posts_page.tpl index 89cb94e..bb4ffe6 100644 --- a/client/html/posts_page.tpl +++ b/client/html/posts_page.tpl @@ -4,11 +4,7 @@ <% for (let post of ctx.results) { %> <li> <% if (ctx.canViewPosts) { %> - <% if (ctx.searchQuery && ctx.searchQuery.text) { %> - <a class='thumbnail-wrapper' href='/post/<%- encodeURIComponent(post.id) %>/text=<%- encodeURIComponent(ctx.searchQuery.text) %>' title='@<%- post.id %> (<%- post.type %>) Tags: <%- post.tags.map(tag => '#' + tag).join(' ') %>'> - <% } else { %> - <a class='thumbnail-wrapper' href='/post/<%- encodeURIComponent(post.id) %>' title='@<%- post.id %> (<%- post.type %>) Tags: <%- post.tags.map(tag => '#' + tag).join(' ') %>'> - <% } %> + <a class='thumbnail-wrapper' href='<%= ctx.getPostUrl(post.id, ctx.parameters) %>' title='@<%- post.id %> (<%- post.type %>) Tags: <%- post.tags.map(tag => '#' + tag).join(' ') %>'> <% } else { %> <a class='thumbnail-wrapper'> <% } %> @@ -39,7 +35,7 @@ </span> <% } %> </a> - <% if (ctx.searchQuery && ctx.searchQuery.tag) { %> + <% if (ctx.parameters && ctx.parameters.tag) { %> <a data-post-id='<%= post.id %>' class='masstag'> </a> <% } %> diff --git a/client/html/tag_category_row.tpl b/client/html/tag_category_row.tpl index 18897ea..c633464 100644 --- a/client/html/tag_category_row.tpl +++ b/client/html/tag_category_row.tpl @@ -17,7 +17,7 @@ </td> <td class='usages'> <% if (ctx.tagCategory.name) { %> - <a href='/tags/text=category:<%- encodeURIComponent(ctx.tagCategory.name) %>'> + <a href='/tags/query=category:<%- encodeURIComponent(ctx.tagCategory.name) %>'> <%- ctx.tagCategory.tagCount %> </a> <% } else { %> diff --git a/client/html/tag_delete.tpl b/client/html/tag_delete.tpl index 6f53c23..a406b33 100644 --- a/client/html/tag_delete.tpl +++ b/client/html/tag_delete.tpl @@ -2,7 +2,7 @@ <form> <% if (ctx.tag.postCount) { %> <p>For extra <s>paranoia</s> safety, only tags that are unused can be deleted.</p> - <p>Check <a href='/posts/text=<%- encodeURIComponent(ctx.tag.names[0]) %>'>which posts</a> are tagged with <%- ctx.tag.names[0] %>.</p> + <p>Check <a href='/posts/query=<%- encodeURIComponent(ctx.tag.names[0]) %>'>which posts</a> are tagged with <%- ctx.tag.names[0] %>.</p> <% } else { %> <div class='input'> <ul> diff --git a/client/html/tag_summary.tpl b/client/html/tag_summary.tpl index c25b39c..38bb238 100644 --- a/client/html/tag_summary.tpl +++ b/client/html/tag_summary.tpl @@ -36,6 +36,6 @@ <section class='description'> <hr/> <%= ctx.makeMarkdown(ctx.tag.description || 'This tag has no description yet.') %> - <p>This tag has <a href='/posts/text=<%- encodeURIComponent(ctx.tag.names[0]) %>'><%- ctx.tag.postCount %> usages</a>.</p> + <p>This tag has <a href='/posts/query=<%- encodeURIComponent(ctx.tag.names[0]) %>'><%- ctx.tag.postCount %> usages</a>.</p> </section> </div> diff --git a/client/html/tags_header.tpl b/client/html/tags_header.tpl index 6940155..a3d4641 100644 --- a/client/html/tags_header.tpl +++ b/client/html/tags_header.tpl @@ -3,7 +3,7 @@ <div class='input'> <ul> <li> - <%= ctx.makeTextInput({text: 'Search query', id: 'search-text', name: 'search-text', value: ctx.searchQuery.text}) %> + <%= ctx.makeTextInput({text: 'Search query', id: 'search-text', name: 'search-text', value: ctx.parameters.query}) %> </li> </ul> </div> diff --git a/client/html/tags_page.tpl b/client/html/tags_page.tpl index fafc1bb..c819c92 100644 --- a/client/html/tags_page.tpl +++ b/client/html/tags_page.tpl @@ -4,37 +4,37 @@ <thead> <th class='names'> <% if (ctx.query == 'sort:name' || !ctx.query) { %> - <a href='/tags/text=-sort:name'>Tag name(s)</a> + <a href='/tags/query=-sort:name'>Tag name(s)</a> <% } else { %> - <a href='/tags/text=sort:name'>Tag name(s)</a> + <a href='/tags/query=sort:name'>Tag name(s)</a> <% } %> </th> <th class='implications'> <% if (ctx.query == 'sort:implication-count') { %> - <a href='/tags/text=-sort:implication-count'>Implications</a> + <a href='/tags/query=-sort:implication-count'>Implications</a> <% } else { %> - <a href='/tags/text=sort:implication-count'>Implications</a> + <a href='/tags/query=sort:implication-count'>Implications</a> <% } %> </th> <th class='suggestions'> <% if (ctx.query == 'sort:suggestion-count') { %> - <a href='/tags/text=-sort:suggestion-count'>Suggestions</a> + <a href='/tags/query=-sort:suggestion-count'>Suggestions</a> <% } else { %> - <a href='/tags/text=sort:suggestion-count'>Suggestions</a> + <a href='/tags/query=sort:suggestion-count'>Suggestions</a> <% } %> </th> <th class='usages'> <% if (ctx.query == 'sort:usages') { %> - <a href='/tags/text=-sort:usages'>Usages</a> + <a href='/tags/query=-sort:usages'>Usages</a> <% } else { %> - <a href='/tags/text=sort:usages'>Usages</a> + <a href='/tags/query=sort:usages'>Usages</a> <% } %> </th> <th class='edit-time'> <% if (ctx.query == 'sort:last-edit-time') { %> - <a href='/tags/text=-sort:last-edit-time'>Edit time</a> + <a href='/tags/query=-sort:last-edit-time'>Edit time</a> <% } else { %> - <a href='/tags/text=sort:last-edit-time'>Edit time</a> + <a href='/tags/query=sort:last-edit-time'>Edit time</a> <% } %> </th> </thead> diff --git a/client/html/user_summary.tpl b/client/html/user_summary.tpl index 314db77..b2d40ac 100644 --- a/client/html/user_summary.tpl +++ b/client/html/user_summary.tpl @@ -10,9 +10,9 @@ <nav> <p><strong>Quick links</strong></p> <ul> - <li><a href='/posts/text=submit:<%- encodeURIComponent(ctx.user.name) %>'><%- ctx.user.uploadedPostCount %> uploads</a></li> - <li><a href='/posts/text=fav:<%- encodeURIComponent(ctx.user.name) %>'><%- ctx.user.favoritePostCount %> favorites</a></li> - <li><a href='/posts/text=comment:<%- encodeURIComponent(ctx.user.name) %>'><%- ctx.user.commentCount %> comments</a></li> + <li><a href='/posts/query=submit:<%- encodeURIComponent(ctx.user.name) %>'><%- ctx.user.uploadedPostCount %> uploads</a></li> + <li><a href='/posts/query=fav:<%- encodeURIComponent(ctx.user.name) %>'><%- ctx.user.favoritePostCount %> favorites</a></li> + <li><a href='/posts/query=comment:<%- encodeURIComponent(ctx.user.name) %>'><%- ctx.user.commentCount %> comments</a></li> </ul> </nav> @@ -20,8 +20,8 @@ <nav> <p><strong>Only visible to you</strong></p> <ul> - <li><a href='/posts/text=special:liked'><%- ctx.user.likedPostCount %> liked posts</a></li> - <li><a href='/posts/text=special:disliked'><%- ctx.user.dislikedPostCount %> disliked posts</a></li> + <li><a href='/posts/query=special:liked'><%- ctx.user.likedPostCount %> liked posts</a></li> + <li><a href='/posts/query=special:disliked'><%- ctx.user.dislikedPostCount %> disliked posts</a></li> </ul> </nav> <% } %> diff --git a/client/html/users_header.tpl b/client/html/users_header.tpl index 87d1091..5b7d38b 100644 --- a/client/html/users_header.tpl +++ b/client/html/users_header.tpl @@ -3,7 +3,7 @@ <div class='input'> <ul> <li> - <%= ctx.makeTextInput({text: 'Search query', id: 'search-text', name: 'search-text', value: ctx.searchQuery.text}) %> + <%= ctx.makeTextInput({text: 'Search query', id: 'search-text', name: 'search-text', value: ctx.parameters.query}) %> </li> </ul> </div> diff --git a/client/js/controllers/comments_controller.js b/client/js/controllers/comments_controller.js index 0f2684f..7fa490e 100644 --- a/client/js/controllers/comments_controller.js +++ b/client/js/controllers/comments_controller.js @@ -14,11 +14,11 @@ class CommentsController { topNavigation.activate('comments'); this._pageController = new PageController({ - searchQuery: ctx.searchQuery, + parameters: ctx.parameters, getClientUrlForPage: page => { - const searchQuery = Object.assign( - {}, ctx.searchQuery, {page: page}); - return '/comments/' + misc.formatSearchQuery(searchQuery); + const parameters = Object.assign( + {}, ctx.parameters, {page: page}); + return '/comments/' + misc.formatUrlParameters(parameters); }, requestPage: page => { return PostList.search( @@ -63,7 +63,7 @@ class CommentsController { }; module.exports = router => { - router.enter('/comments/:query?', - (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, + router.enter('/comments/:parameters?', + (ctx, next) => { misc.parseUrlParametersRoute(ctx, next); }, (ctx, next) => { new CommentsController(ctx); }); }; diff --git a/client/js/controllers/help_controller.js b/client/js/controllers/help_controller.js index f7dcafa..4c42d0b 100644 --- a/client/js/controllers/help_controller.js +++ b/client/js/controllers/help_controller.js @@ -15,9 +15,9 @@ module.exports = router => { new HelpController(); }); router.enter('/help/:section', (ctx, next) => { - new HelpController(ctx.params.section); + new HelpController(ctx.parameters.section); }); router.enter('/help/:section/:subsection', (ctx, next) => { - new HelpController(ctx.params.section, ctx.params.subsection); + new HelpController(ctx.parameters.section, ctx.parameters.subsection); }); }; diff --git a/client/js/controllers/page_controller.js b/client/js/controllers/page_controller.js index a7154ee..6a490ee 100644 --- a/client/js/controllers/page_controller.js +++ b/client/js/controllers/page_controller.js @@ -8,7 +8,7 @@ class PageController { constructor(ctx) { const extendedContext = { getClientUrlForPage: ctx.getClientUrlForPage, - searchQuery: ctx.searchQuery, + parameters: ctx.parameters, }; ctx.headerContext = Object.assign({}, extendedContext); diff --git a/client/js/controllers/password_reset_controller.js b/client/js/controllers/password_reset_controller.js index 00a288c..f291bd4 100644 --- a/client/js/controllers/password_reset_controller.js +++ b/client/js/controllers/password_reset_controller.js @@ -58,6 +58,6 @@ module.exports = router => { }); router.enter(/\/password-reset\/([^:]+):([^:]+)$/, (ctx, next) => { ctx.controller = new PasswordResetFinishController( - ctx.params[0], ctx.params[1]); + ctx.parameters[0], ctx.parameters[1]); }); }; diff --git a/client/js/controllers/post_controller.js b/client/js/controllers/post_controller.js index c00e87b..a9c6dd2 100644 --- a/client/js/controllers/post_controller.js +++ b/client/js/controllers/post_controller.js @@ -11,14 +11,14 @@ const PostView = require('../views/post_view.js'); const EmptyView = require('../views/empty_view.js'); class PostController { - constructor(id, editMode, searchQuery) { + constructor(id, editMode, parameters) { topNavigation.activate('posts'); Promise.all([ Post.get(id), PostList.getAround( id, this._decorateSearchQuery( - searchQuery ? searchQuery.text : '')), + parameters ? parameters.query : '')), ]).then(responses => { const [post, aroundResponse] = responses; this._post = post; @@ -30,7 +30,7 @@ class PostController { canEditPosts: api.hasPrivilege('posts:edit'), canListComments: api.hasPrivilege('comments:list'), canCreateComments: api.hasPrivilege('comments:create'), - searchQuery: searchQuery, + parameters: parameters, }); if (this._view.sidebarControl) { this._view.sidebarControl.addEventListener( @@ -149,17 +149,17 @@ class PostController { } module.exports = router => { - router.enter('/post/:id/edit/:query?', - (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, + router.enter('/post/:id/edit/:parameters?', + (ctx, next) => { misc.parseUrlParametersRoute(ctx, next); }, (ctx, next) => { ctx.controller = new PostController( - ctx.params.id, true, ctx.searchQuery); + ctx.parameters.id, true, ctx.parameters); }); router.enter( - '/post/:id/:query?', - (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, + '/post/:id/:parameters?', + (ctx, next) => { misc.parseUrlParametersRoute(ctx, next); }, (ctx, next) => { ctx.controller = new PostController( - ctx.params.id, false, ctx.searchQuery); + ctx.parameters.id, false, ctx.parameters); }); }; diff --git a/client/js/controllers/post_list_controller.js b/client/js/controllers/post_list_controller.js index 16f3765..8219520 100644 --- a/client/js/controllers/post_list_controller.js +++ b/client/js/controllers/post_list_controller.js @@ -19,15 +19,15 @@ class PostListController { this._ctx = ctx; this._pageController = new PageController({ - searchQuery: ctx.searchQuery, + parameters: ctx.parameters, getClientUrlForPage: page => { - const searchQuery = Object.assign( - {}, ctx.searchQuery, {page: page}); - return '/posts/' + misc.formatSearchQuery(searchQuery); + const parameters = Object.assign( + {}, ctx.parameters, {page: page}); + return '/posts/' + misc.formatUrlParameters(parameters); }, requestPage: page => { return PostList.search( - this._decorateSearchQuery(ctx.searchQuery.text), + this._decorateSearchQuery(ctx.parameters.query), page, 40, fields); }, headerRenderer: headerCtx => { @@ -51,7 +51,7 @@ class PostListController { } get _massTagTags() { - return (this._ctx.searchQuery.tag || '').split(/\s+/).filter(s => s); + return (this._ctx.parameters.tag || '').split(/\s+/).filter(s => s); } _evtTag(e) { @@ -91,7 +91,7 @@ class PostListController { module.exports = router => { router.enter( - '/posts/:query?', - (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, + '/posts/:parameters?', + (ctx, next) => { misc.parseUrlParametersRoute(ctx, next); }, (ctx, next) => { ctx.controller = new PostListController(ctx); }); }; diff --git a/client/js/controllers/tag_categories_controller.js b/client/js/controllers/tag_categories_controller.js index f33438d..f676eb4 100644 --- a/client/js/controllers/tag_categories_controller.js +++ b/client/js/controllers/tag_categories_controller.js @@ -2,7 +2,6 @@ const api = require('../api.js'); const tags = require('../tags.js'); -const misc = require('../util/misc.js'); const TagCategoryList = require('../models/tag_category_list.js'); const topNavigation = require('../models/top_navigation.js'); const TagCategoriesView = require('../views/tag_categories_view.js'); diff --git a/client/js/controllers/tag_controller.js b/client/js/controllers/tag_controller.js index 08a3c09..9d46744 100644 --- a/client/js/controllers/tag_controller.js +++ b/client/js/controllers/tag_controller.js @@ -10,10 +10,10 @@ const EmptyView = require('../views/empty_view.js'); class TagController { constructor(ctx, section) { - Tag.get(ctx.params.name).then(tag => { + Tag.get(ctx.parameters.name).then(tag => { topNavigation.activate('tags'); - this._name = ctx.params.name; + this._name = ctx.parameters.name; tag.addEventListener('change', e => this._evtSaved(e)); const categories = {}; diff --git a/client/js/controllers/tag_list_controller.js b/client/js/controllers/tag_list_controller.js index 7492398..f059771 100644 --- a/client/js/controllers/tag_list_controller.js +++ b/client/js/controllers/tag_list_controller.js @@ -16,14 +16,14 @@ class TagListController { topNavigation.activate('tags'); this._pageController = new PageController({ - searchQuery: ctx.searchQuery, + parameters: ctx.parameters, getClientUrlForPage: page => { - const searchQuery = Object.assign( - {}, ctx.searchQuery, {page: page}); - return '/tags/' + misc.formatSearchQuery(searchQuery); + const parameters = Object.assign( + {}, ctx.parameters, {page: page}); + return '/tags/' + misc.formatUrlParameters(parameters); }, requestPage: page => { - return TagList.search(ctx.searchQuery.text, page, 50, fields); + return TagList.search(ctx.parameters.query, page, 50, fields); }, headerRenderer: headerCtx => { Object.assign(headerCtx, { @@ -49,7 +49,7 @@ class TagListController { module.exports = router => { router.enter( - '/tags/:query?', - (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, + '/tags/:parameters?', + (ctx, next) => { misc.parseUrlParametersRoute(ctx, next); }, (ctx, next) => { ctx.controller = new TagListController(ctx); }); }; diff --git a/client/js/controllers/user_controller.js b/client/js/controllers/user_controller.js index 31a562b..e068bfd 100644 --- a/client/js/controllers/user_controller.js +++ b/client/js/controllers/user_controller.js @@ -11,11 +11,11 @@ const EmptyView = require('../views/empty_view.js'); class UserController { constructor(ctx, section) { - User.get(ctx.params.name).then(user => { + User.get(ctx.parameters.name).then(user => { const isLoggedIn = api.isLoggedIn(user); const infix = isLoggedIn ? 'self' : 'any'; - this._name = ctx.params.name; + this._name = ctx.parameters.name; user.addEventListener('change', e => this._evtSaved(e)); const myRankIndex = api.user ? diff --git a/client/js/controllers/user_list_controller.js b/client/js/controllers/user_list_controller.js index e9f0894..31d0e72 100644 --- a/client/js/controllers/user_list_controller.js +++ b/client/js/controllers/user_list_controller.js @@ -13,14 +13,14 @@ class UserListController { topNavigation.activate('users'); this._pageController = new PageController({ - searchQuery: ctx.searchQuery, + parameters: ctx.parameters, getClientUrlForPage: page => { - const searchQuery = Object.assign( - {}, ctx.searchQuery, {page: page}); - return '/users/' + misc.formatSearchQuery(searchQuery); + const parameters = Object.assign( + {}, ctx.parameters, {page: page}); + return '/users/' + misc.formatUrlParameters(parameters); }, requestPage: page => { - return UserList.search(ctx.searchQuery.text, page); + return UserList.search(ctx.parameters.query, page); }, headerRenderer: headerCtx => { return new UsersHeaderView(headerCtx); @@ -41,7 +41,7 @@ class UserListController { module.exports = router => { router.enter( - '/users/:query?', - (ctx, next) => { misc.parseSearchQueryRoute(ctx, next); }, + '/users/:parameters?', + (ctx, next) => { misc.parseUrlParametersRoute(ctx, next); }, (ctx, next) => { ctx.controller = new UserListController(ctx); }); }; diff --git a/client/js/router.js b/client/js/router.js index 426d6d4..490b804 100644 --- a/client/js/router.js +++ b/client/js/router.js @@ -39,7 +39,7 @@ class Context { this.title = document.title; this.state = state || {}; this.state.path = path; - this.params = {}; + this.parameters = {}; } pushState() { @@ -61,14 +61,14 @@ class Route { middleware(fn) { return (ctx, next) => { - if (this.match(ctx.path, ctx.params)) { + if (this.match(ctx.path, ctx.parameters)) { return fn(ctx, next); } next(); }; } - match(path, params) { + match(path, parameters) { const keys = this.keys; const qsIndex = path.indexOf('?'); const pathname = ~qsIndex ? path.slice(0, qsIndex) : path; @@ -81,8 +81,9 @@ class Route { 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; + if (val !== undefined || + !(hasOwnProperty.call(parameters, key.name))) { + parameters[key.name] = val; } } diff --git a/client/js/util/misc.js b/client/js/util/misc.js index 5e2297a..a3efede 100644 --- a/client/js/util/misc.js +++ b/client/js/util/misc.js @@ -113,7 +113,7 @@ function formatMarkdown(text) { '$1[$2]($2)'); text = text.replace(/\]\(@(\d+)\)/g, '](/post/$1)'); text = text.replace(/\]\(\+([a-zA-Z0-9_-]+)\)/g, '](/user/$1)'); - text = text.replace(/\]\(#([a-zA-Z0-9_-]+)\)/g, '](/posts/text=$1)'); + text = text.replace(/\]\(#([a-zA-Z0-9_-]+)\)/g, '](/posts/query=$1)'); return text; }; @@ -131,7 +131,7 @@ function formatMarkdown(text) { //search permalinks text = text.replace( /\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/ig, - '<a href="/posts/text=$1"><code>$1</code></a>'); + '<a href="/posts/query=$1"><code>$1</code></a>'); //spoilers text = text.replace( /\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/ig, @@ -149,10 +149,13 @@ function formatMarkdown(text) { return postDecorator(marked(preDecorator(text), options)); } -function formatSearchQuery(dict) { +function formatUrlParameters(dict) { let result = []; for (let key of Object.keys(dict)) { const value = dict[key]; + if (key === 'parameters') { + continue; + } if (value) { result.push(`${key}=${value}`); } @@ -160,19 +163,23 @@ function formatSearchQuery(dict) { return result.join(';'); } -function parseSearchQuery(query) { +function parseUrlParameters(query) { let result = {}; for (let word of (query || '').split(/;/)) { const [key, value] = word.split(/=/, 2); result[key] = value; } - result.text = result.text || ''; + result.query = result.query || ''; result.page = parseInt(result.page || '1'); return result; } -function parseSearchQueryRoute(ctx, next) { - ctx.searchQuery = parseSearchQuery(ctx.params.query || ''); +function parseUrlParametersRoute(ctx, next) { + // ctx.parameters = {"user":...,"action":...} from /users/:user/:action + // ctx.parameters.parameters = value of :parameters as per /url/:parameters + Object.assign( + ctx.parameters, + parseUrlParameters(ctx.parameters.parameters)); next(); } @@ -235,9 +242,9 @@ function escapeHtml(unsafe) { module.exports = { range: range, - formatSearchQuery: formatSearchQuery, - parseSearchQuery: parseSearchQuery, - parseSearchQueryRoute: parseSearchQueryRoute, + formatUrlParameters: formatUrlParameters, + parseUrlParameters: parseUrlParameters, + parseUrlParametersRoute: parseUrlParametersRoute, formatRelativeTime: formatRelativeTime, formatFileSize: formatFileSize, formatMarkdown: formatMarkdown, diff --git a/client/js/util/views.js b/client/js/util/views.js index a8af438..9561a27 100644 --- a/client/js/util/views.js +++ b/client/js/util/views.js @@ -146,6 +146,22 @@ function makeColorInput(options) { 'label', {class: 'color'}, colorInput + textInput); } +function getPostUrl(id, parameters) { + let url = '/post/' + encodeURIComponent(id); + if (parameters && parameters.query) { + url += '/query=' + encodeURIComponent(parameters.query); + } + return url; +} + +function getPostEditUrl(id, parameters) { + let url = '/post/' + encodeURIComponent(id) + '/edit'; + if (parameters && parameters.query) { + url += '/query=' + encodeURIComponent(parameters.query); + } + return url; +} + function makePostLink(id) { const text = '@' + id; return api.hasPrivilege('posts:view') ? @@ -303,6 +319,8 @@ function getTemplate(templatePath) { ctx = {}; } Object.assign(ctx, { + getPostUrl: getPostUrl, + getPostEditUrl: getPostEditUrl, makeRelativeTime: makeRelativeTime, makeFileSize: makeFileSize, makeMarkdown: makeMarkdown, diff --git a/client/js/views/endless_page_view.js b/client/js/views/endless_page_view.js index 5965642..142a6dc 100644 --- a/client/js/views/endless_page_view.js +++ b/client/js/views/endless_page_view.js @@ -30,7 +30,7 @@ class EndlessPageView { ctx.headerRenderer(ctx.headerContext); } - this._loadPage(ctx, ctx.searchQuery.page, true); + this._loadPage(ctx, ctx.parameters.page, true); this._probePageLoad(ctx); } diff --git a/client/js/views/home_view.js b/client/js/views/home_view.js index a8d151b..3278972 100644 --- a/client/js/views/home_view.js +++ b/client/js/views/home_view.js @@ -87,8 +87,8 @@ class HomeView { _evtFormSubmit(e) { e.preventDefault(); this._searchInputNode.blur(); - router.show('/posts/' + misc.formatSearchQuery({ - text: this._searchInputNode.value})); + router.show('/posts/' + misc.formatUrlParameters({ + query: this._searchInputNode.value})); } } diff --git a/client/js/views/manual_page_view.js b/client/js/views/manual_page_view.js index 4d896e9..1ceac67 100644 --- a/client/js/views/manual_page_view.js +++ b/client/js/views/manual_page_view.js @@ -63,7 +63,7 @@ class ManualPageView { const pageHeaderHolderNode = sourceNode.querySelector('.page-header-holder'); const pageNavNode = sourceNode.querySelector('.page-nav'); - const currentPage = ctx.searchQuery.page; + const currentPage = ctx.parameters.page; ctx.headerContext.hostNode = pageHeaderHolderNode; if (ctx.headerRenderer) { diff --git a/client/js/views/posts_header_view.js b/client/js/views/posts_header_view.js index 5958e2a..6824b87 100644 --- a/client/js/views/posts_header_view.js +++ b/client/js/views/posts_header_view.js @@ -53,7 +53,7 @@ class PostsHeaderView { 'click', e => this._evtStopTaggingClick(e)); this._massTagFormNode.addEventListener( 'submit', e => this._evtMassTagFormSubmit(e)); - this._toggleMassTagVisibility(!!ctx.searchQuery.tag); + this._toggleMassTagVisibility(!!ctx.parameters.tag); } } @@ -96,9 +96,9 @@ class PostsHeaderView { _evtStopTaggingClick(e) { e.preventDefault(); - router.show('/posts/' + misc.formatSearchQuery({ - text: this._ctx.searchQuery.text, - page: this._ctx.searchQuery.page, + router.show('/posts/' + misc.formatUrlParameters({ + query: this._ctx.parameters.query, + page: this._ctx.parameters.page, })); } @@ -117,7 +117,7 @@ class PostsHeaderView { e.preventDefault(); const text = this._queryInputNode.value; this._queryInputNode.blur(); - router.show('/posts/' + misc.formatSearchQuery({text: text})); + router.show('/posts/' + misc.formatUrlParameters({query: text})); } _evtMassTagFormSubmit(e) { @@ -125,10 +125,10 @@ class PostsHeaderView { const text = this._queryInputNode.value; const tag = this._massTagInputNode.value; this._massTagInputNode.blur(); - router.show('/posts/' + misc.formatSearchQuery({ - text: text, + router.show('/posts/' + misc.formatUrlParameters({ + query: text, tag: tag, - page: this._ctx.searchQuery.page, + page: this._ctx.parameters.page, })); } } diff --git a/client/js/views/tags_header_view.js b/client/js/views/tags_header_view.js index 61ea8d2..a9babc2 100644 --- a/client/js/views/tags_header_view.js +++ b/client/js/views/tags_header_view.js @@ -37,8 +37,8 @@ class TagsHeaderView { e.preventDefault(); this._queryInputNode.blur(); router.show( - '/tags/' + misc.formatSearchQuery({ - text: this._queryInputNode.value, + '/tags/' + misc.formatUrlParameters({ + query: this._queryInputNode.value, })); } } diff --git a/client/js/views/users_header_view.js b/client/js/views/users_header_view.js index 2284ba7..8678025 100644 --- a/client/js/views/users_header_view.js +++ b/client/js/views/users_header_view.js @@ -31,8 +31,8 @@ class UsersHeaderView { e.preventDefault(); this._queryInputNode.blur(); router.show( - '/users/' + misc.formatSearchQuery({ - text: this._queryInputNode.value, + '/users/' + misc.formatUrlParameters({ + query: this._queryInputNode.value, })); } }