diff --git a/client/js/controllers/tags_controller.js b/client/js/controllers/tags_controller.js index 91330ba4..ef2d94db 100644 --- a/client/js/controllers/tags_controller.js +++ b/client/js/controllers/tags_controller.js @@ -185,10 +185,9 @@ class TagsController { pageController.run({ state: ctx.state, requestPage: page => { + const text = ctx.searchQuery.text; return api.get( - '/tags/?query={text}&page={page}&pageSize=50'.format({ - text: ctx.searchQuery.text, - page: page})); + `/tags/?query=${text}&page=${page}&pageSize=50`); }, clientUrl: '/tags/' + misc.formatSearchQuery({ text: ctx.searchQuery.text, page: '{page}'}), diff --git a/client/js/controllers/users_controller.js b/client/js/controllers/users_controller.js index 53f485e8..96d609af 100644 --- a/client/js/controllers/users_controller.js +++ b/client/js/controllers/users_controller.js @@ -67,10 +67,9 @@ class UsersController { pageController.run({ state: ctx.state, requestPage: page => { + const text = ctx.searchQuery.text; return api.get( - '/users/?query={text}&page={page}&pageSize=30'.format({ - text: ctx.searchQuery.text, - page: page})); + `/users/?query=${text}&page=${page}&pageSize=30`); }, clientUrl: '/users/' + misc.formatSearchQuery({ text: ctx.searchQuery.text, page: '{page}'}), diff --git a/client/js/controls/tag_auto_complete_control.js b/client/js/controls/tag_auto_complete_control.js index 7bb9090c..6bbe8d87 100644 --- a/client/js/controls/tag_auto_complete_control.js +++ b/client/js/controls/tag_auto_complete_control.js @@ -1,5 +1,6 @@ 'use strict'; +const unindent = require('../util/misc.js').unindent; const lodash = require('lodash'); const tags = require('../tags.js'); const AutoCompleteControl = require('./auto_complete_control.js'); @@ -26,12 +27,14 @@ class TagAutoCompleteControl extends AutoCompleteControl { return kv2[1].usages - kv1[1].usages; }) .map(kv => { + const category = kv[1].category; + const origName = tags.getOriginalTagName(kv[0]); + const usages = kv[1].usages; return { - caption: - '{1} ({2})'.format( - kv[1].category, - tags.getOriginalTagName(kv[0]), - kv[1].usages), + caption: unindent` + + ${origName} (${usages}) + `, value: kv[0], }; }); diff --git a/client/js/tags.js b/client/js/tags.js index 359d997a..09ff9252 100644 --- a/client/js/tags.js +++ b/client/js/tags.js @@ -1,7 +1,6 @@ 'use strict'; const request = require('superagent'); -const util = require('./util/misc.js'); const events = require('./events.js'); let _tags = null; @@ -66,7 +65,7 @@ function _refreshStylesheet() { document.head.appendChild(_stylesheet); for (let category of getAllCategories()) { _stylesheet.sheet.insertRule( - '.tag-{0} { color: {1} }'.format(category.name, category.color), + `.tag-${category.name} { color: ${category.color} }`, _stylesheet.sheet.cssRules.length); } } diff --git a/client/js/util/misc.js b/client/js/util/misc.js index af333642..423fe393 100644 --- a/client/js/util/misc.js +++ b/client/js/util/misc.js @@ -57,7 +57,7 @@ function formatSearchQuery(dict) { for (let key of Object.keys(dict)) { const value = dict[key]; if (value) { - result.push('{0}={1}'.format(key, value)); + result.push(`${key}=${value}`); } } return result.join(';'); @@ -79,10 +79,34 @@ function parseSearchQueryRoute(ctx, next) { next(); } +function unindent(callSite, ...args) { + function format(str) { + let size = -1; + return str.replace(/\n(\s+)/g, (m, m1) => { + if (size < 0) { + size = m1.replace(/\t/g, ' ').length; + } + return "\n" + m1.slice(Math.min(m1.length, size)); + }); + } + if (typeof callSite === 'string') { + return format(callSite); + } + if (typeof callSite === 'function') { + return (...args) => format(callSite(...args)); + } + let output = callSite + .slice(0, args.length + 1) + .map((text, i) => (i === 0 ? '' : args[i - 1]) + text) + .join(''); + return format(output); +} + module.exports = { range: range, formatSearchQuery: formatSearchQuery, parseSearchQuery: parseSearchQuery, parseSearchQueryRoute: parseSearchQueryRoute, formatRelativeTime: formatRelativeTime, + unindent: unindent, }; diff --git a/client/js/util/polyfill.js b/client/js/util/polyfill.js index f11d13cd..606d29d7 100644 --- a/client/js/util/polyfill.js +++ b/client/js/util/polyfill.js @@ -22,25 +22,6 @@ Promise.prototype.always = function(onResolveOrReject) { }); }; -// non standard -if (!String.prototype.format) { - String.prototype.format = function() { - let str = this.toString(); - if (!arguments.length) { - return str; - } - const type = typeof arguments[0]; - const args = (type == 'string' || type == 'number') ? - arguments : arguments[0]; - for (let arg in args) { - str = str.replace( - new RegExp('\\{' + arg + '\\}', 'gi'), - () => { return args[arg]; }); - } - return str; - }; -} - // non standard Number.prototype.between = function(a, b, inclusive) { const min = Math.min(a, b); diff --git a/client/js/util/views.js b/client/js/util/views.js index 2e032edc..d432ee1f 100644 --- a/client/js/util/views.js +++ b/client/js/util/views.js @@ -36,7 +36,7 @@ function makeThumbnail(url) { 'span', { class: 'thumbnail', - style: 'background-image: url(\'{0}\')'.format(url) + style: `background-image: url(\'${url}\')`, }, makeVoidElement('img', {alt: 'thumbnail', src: url})); } @@ -164,18 +164,17 @@ function _serializeElement(name, attributes) { attributes[key] === undefined) { return ''; } - return '{0}="{1}"'.format(key, attributes[key]); + return `${key}="${attributes[key]}"`; })) .join(' '); } function makeNonVoidElement(name, attributes, content) { - return '<{0}>{1}'.format( - _serializeElement(name, attributes), content, name); + return `<${_serializeElement(name, attributes)}>${content}`; } function makeVoidElement(name, attributes) { - return '<{0}/>'.format(_serializeElement(name, attributes)); + return `<${_serializeElement(name, attributes)}/>`; } function _messageHandler(target, message, className) { diff --git a/client/js/views/endless_page_view.js b/client/js/views/endless_page_view.js index c4e36463..6c54d3b0 100644 --- a/client/js/views/endless_page_view.js +++ b/client/js/views/endless_page_view.js @@ -4,6 +4,10 @@ const page = require('page'); const events = require('../events.js'); const views = require('../util/views.js'); +function _formatUrl(url, page) { + return url.replace('{page}', page); +} + class EndlessPageView { constructor() { this._holderTemplate = views.getTemplate('endless-pager'); @@ -51,7 +55,7 @@ class EndlessPageView { let topPageNumber = parseInt(topPageNode.getAttribute('data-page')); if (topPageNumber !== this.currentPage) { page.replace( - ctx.clientUrl.format({page: topPageNumber}), + _formatUrl(ctx.clientUrl, topPageNumber), null, false, false); diff --git a/client/js/views/manual_page_view.js b/client/js/views/manual_page_view.js index 9e176f8f..baeafc21 100644 --- a/client/js/views/manual_page_view.js +++ b/client/js/views/manual_page_view.js @@ -6,6 +6,10 @@ const keyboard = require('../util/keyboard.js'); const misc = require('../util/misc.js'); const views = require('../util/views.js'); +function _formatUrl(url, page) { + return url.replace('{page}', page); +} + function _removeConsecutiveDuplicates(a) { return a.filter((item, pos, ary) => { return !pos || item != ary[pos - 1]; @@ -43,7 +47,7 @@ function _getPages(currentPage, pageNumbers, clientUrl) { } pages.push({ number: page, - link: clientUrl.format({page: page}), + link: _formatUrl(clientUrl, page), active: currentPage === page, }); lastPage = page; @@ -80,19 +84,19 @@ class ManualPageView { keyboard.bind(['a', 'left'], () => { if (currentPage > 1) { - page.show(ctx.clientUrl.format({page: currentPage - 1})); + page.show(_formatUrl(ctx.clientUrl, currentPage - 1)); } }); keyboard.bind(['d', 'right'], () => { if (currentPage < totalPages) { - page.show(ctx.clientUrl.format({page: currentPage + 1})); + page.show(_formatUrl(ctx.clientUrl, currentPage + 1)); } }); if (response.total) { views.showView(pageNav, this._navTemplate({ - prevLink: ctx.clientUrl.format({page: currentPage - 1}), - nextLink: ctx.clientUrl.format({page: currentPage + 1}), + prevLink: _formatUrl(ctx.clientUrl, currentPage - 1), + nextLink: _formatUrl(ctx.clientUrl, currentPage + 1), prevLinkActive: currentPage > 1, nextLinkActive: currentPage < totalPages, pages: pages,