diff --git a/assets/typescript/Comments.ts b/assets/typescript/Comments.ts
index db08dfe6..936e5c2d 100644
--- a/assets/typescript/Comments.ts
+++ b/assets/typescript/Comments.ts
@@ -76,7 +76,7 @@ function commentDelete(commentId: number, onSuccess: (info: CommentDeletionInfo)
else if (!message && onSuccess)
onSuccess(json);
});
- xhr.open('GET', `/comments.php?m=delete&c=${commentId}&csrf=${getCSRFToken('comments')}`);
+ xhr.open('GET', urlFormat('comments-delete', [{name:'comment',value:commentId}]));
xhr.setRequestHeader('X-Misuzu-XHR', 'comments');
xhr.send();
}
@@ -122,7 +122,7 @@ function commentPost(formData: FormData, onSuccess: (comment: CommentPostInfo) =
onSuccess(json);
});
- xhr.open('POST', '/comments.php?m=create');
+ xhr.open('POST', urlFormat('comment-create'));
xhr.setRequestHeader('X-Misuzu-XHR', 'comments');
xhr.send(formData);
}
@@ -202,8 +202,8 @@ function commentConstruct(comment: CommentPostInfo, layer: number = 0): HTMLElem
// container
const commentAvatar: HTMLAnchorElement = commentContainer.appendChild(document.createElement('a'));
commentAvatar.className = 'avatar comment__avatar';
- commentAvatar.href = '/profile.php?u=' + comment.user_id;
- commentAvatar.style.backgroundImage = `url('/user-assets.php?m=avatar&u=${comment.user_id}')`;
+ commentAvatar.href = urlFormat('user-profile', [{name:'user',value:comment.user_id}]);
+ commentAvatar.style.backgroundImage = "url('{0}')".replace('{0}', urlFormat('user-avatar', [{name:'user',value:comment.user_id}]));
const commentContent: HTMLDivElement = commentContainer.appendChild(document.createElement('div'));
commentContent.className = 'comment__content';
@@ -303,7 +303,7 @@ function commentConstruct(comment: CommentPostInfo, layer: number = 0): HTMLElem
// reply container
const replyAvatar: HTMLDivElement = replyContainer.appendChild(document.createElement('div'));
replyAvatar.className = 'avatar comment__avatar';
- replyAvatar.style.backgroundImage = `url('/user-assets.php?m=avatar&u=${comment.user_id}')`;
+ replyAvatar.style.backgroundImage = "url('{0}')".replace('{0}', urlFormat('user-avatar', [{name:'user',value:comment.user_id}]));
const replyContent: HTMLDivElement = replyContainer.appendChild(document.createElement('div'));
replyContent.className = 'comment__content';
@@ -424,7 +424,7 @@ function commentVote(
else if (!message && onSuccess)
onSuccess(json);
};
- xhr.open('GET', `/comments.php?m=vote&c=${commentId}&v=${vote}&csrf=${getCSRFToken('comments')}`);
+ xhr.open('GET', urlFormat('comment-vote', [{name: 'comment', value: commentId}, {name: 'vote', value: vote}]));
xhr.setRequestHeader('X-Misuzu-XHR', 'comments');
xhr.send();
}
@@ -500,7 +500,7 @@ function commentPin(
else if (!message && onSuccess)
onSuccess(json);
};
- xhr.open('GET', `/comments.php?m=${mode}&c=${commentId}&csrf=${getCSRFToken('comments')}`);
+ xhr.open('GET', urlFormat(`comment-${mode}`, [{name: 'comment', value: commentId}]));
xhr.setRequestHeader('X-Misuzu-XHR', 'comments');
xhr.send();
}
diff --git a/assets/typescript/FormUtilities.ts b/assets/typescript/FormUtilities.ts
index 9d3d5675..6532624c 100644
--- a/assets/typescript/FormUtilities.ts
+++ b/assets/typescript/FormUtilities.ts
@@ -73,7 +73,8 @@ function getCSRF(realm: string): CSRFToken {
}
function getCSRFToken(realm: string): string {
- return getCSRF(realm).token || '';
+ const token: CSRFToken = getCSRF(realm);
+ return token ? token.token : '';
}
function setCSRF(realm: string, token: string): void {
diff --git a/assets/typescript/UrlRegistry.ts b/assets/typescript/UrlRegistry.ts
new file mode 100644
index 00000000..95696c06
--- /dev/null
+++ b/assets/typescript/UrlRegistry.ts
@@ -0,0 +1,91 @@
+interface UrlRegistryVariable {
+ name: string;
+ value: string;
+}
+
+interface UrlRegistryEntryQuery {
+ name: string;
+ value: string;
+}
+
+interface UrlRegistryEntry {
+ name: string;
+ path: string;
+ query: UrlRegistryEntryQuery[];
+ fragment: string;
+}
+
+let urlRegistryTable: UrlRegistryEntry[] = [];
+
+function getRawUrlRegistry(): UrlRegistryEntry[]
+{
+ const urlListElement: HTMLElement = document.getElementById('js-urls-list') as HTMLElement;
+
+ if (!urlListElement)
+ return null;
+
+ return JSON.parse(urlListElement.textContent) as UrlRegistryEntry[];
+}
+
+function urlRegistryInit(): void
+{
+ urlRegistryTable = getRawUrlRegistry();
+}
+
+function urlFormat(name: string, vars: UrlRegistryVariable[] = []): string
+{
+ const entry: UrlRegistryEntry = urlRegistryTable.find(x => x.name == name);
+
+ if (!entry || !entry.path) {
+ return '';
+ }
+
+ const splitUrl: string[] = entry.path.split('/');
+
+ for (let i = 0; i < splitUrl.length; i++) {
+ splitUrl[i] = urlVariable(splitUrl[i], vars);
+ }
+
+ let url: string = splitUrl.join('/');
+
+ if (entry.query) {
+ url += '?';
+
+ for (let i = 0; i < entry.query.length; i++) {
+ const query: UrlRegistryEntryQuery = entry.query[i],
+ value: string = urlVariable(query.value, vars);
+
+ if (!value || (query.name === 'page' && parseInt(value) < 2)) {
+ continue;
+ }
+
+ url += `${query.name}=${value}&`;
+ }
+
+ url = url.replace(/^[\?\&]+|[\?\&]+$/g, '');
+ }
+
+ if (entry.fragment) {
+ url += ('#' + urlVariable(entry.fragment, vars)).replace(/[\#]+$/g, '');
+ }
+
+ return url;
+}
+
+function urlVariable(value: string, vars: UrlRegistryVariable[]): string
+{
+ if (value[0] === '<' && value.slice(-1) === '>') {
+ const urvar: UrlRegistryVariable = vars.find(x => x.name == value.slice(1, -1));
+ return urvar ? urvar.value : '';
+ }
+
+ if (value[0] === '[' && value.slice(-1) === ']') {
+ return ''; // not sure if there's a proper substitute for this, should probably resolve these in url_list
+ }
+
+ if (value[0] === '{' && value.slice(-1) === '}') {
+ return getCSRFToken(value.slice(1, -1));
+ }
+
+ return value;
+}
diff --git a/assets/typescript/UserRelations.ts b/assets/typescript/UserRelations.ts
index e600672f..942a5da0 100644
--- a/assets/typescript/UserRelations.ts
+++ b/assets/typescript/UserRelations.ts
@@ -121,7 +121,7 @@ function userRelationSet(
else if (!message && onSuccess)
onSuccess(json);
});
- xhr.open('GET', `/relations.php?u=${userId}&m=${relationType}`);
+ xhr.open('GET', urlFormat('user-relation-create', [{name: 'user', value: userId}, {name: 'type', value: relationType.toString()}]));
xhr.setRequestHeader('X-Misuzu-XHR', 'user_relation');
xhr.setRequestHeader('X-Misuzu-CSRF', getCSRFToken('user_relation'));
xhr.send();
diff --git a/assets/typescript/misuzu.ts b/assets/typescript/misuzu.ts
index b4aaee7a..c1848447 100644
--- a/assets/typescript/misuzu.ts
+++ b/assets/typescript/misuzu.ts
@@ -7,6 +7,7 @@
///
///
///
+///
declare const timeago: any;
declare const hljs: any;
@@ -15,10 +16,13 @@ let loginFormAvatarTimeout: number = 0;
// Initialisation process.
window.addEventListener('load', () => {
+ console.log("%c __ ____\n / |/ (_)______ ______ __ __\n / /|_/ / / ___/ / / /_ / / / / /\n / / / / (__ ) /_/ / / /_/ /_/ /\n/_/ /_/_/____/\\__,_/ /___/\\__,_/\nhttps://github.com/flashwave/misuzu", 'color: #8559a5');
+
timeago().render(document.querySelectorAll('time'));
hljs.initHighlighting();
initCSRF();
+ urlRegistryInit();
userInit();
userRelationsInit();
@@ -74,9 +78,9 @@ function loginFormUpdateAvatar(avatarElement: HTMLElement, usernameElement: HTML
if (xhr.readyState !== 4)
return;
- avatarElement.style.backgroundImage = `url('/user-assets.php?m=avatar&u=${xhr.responseText}')`;
+ avatarElement.style.backgroundImage = "url('{0}')".replace('{0}', urlFormat('user-avatar', [{name: 'user', value: xhr.responseText}]));
});
- xhr.open('GET', `/auth.php?m=get_user&u=${encodeURI(usernameElement.value)}`);
+ xhr.open('GET', urlFormat('auth-resolve-user', [{name: 'username', value: encodeURI(usernameElement.value)}]));
xhr.send();
}
@@ -150,7 +154,7 @@ function loginModal(): boolean {
const container: HTMLFormElement = element.appendChild(document.createElement('form'));
container.className = 'container messagebox__container auth js-login-form';
container.method = 'post';
- container.action = '/auth.php';
+ container.action = urlFormat('auth-login');
const titleElement = container.appendChild(document.createElement('div')),
titleBackground = titleElement.appendChild(document.createElement('div')),
@@ -162,7 +166,7 @@ function loginModal(): boolean {
const authAvatar: HTMLDivElement = titleHeader.appendChild(document.createElement('div'));
authAvatar.className = 'avatar auth__avatar';
- authAvatar.style.backgroundImage = "url('/user-assets.php?u=0&m=avatar')";
+ authAvatar.style.backgroundImage = "url('{0}')".replace('{0}', urlFormat('user-avatar'));
const hiddenMode: HTMLInputElement = container.appendChild(document.createElement('input'));
hiddenMode.type = 'hidden';
diff --git a/src/url.php b/src/url.php
index 67b45458..332f0508 100644
--- a/src/url.php
+++ b/src/url.php
@@ -17,6 +17,7 @@ define('MSZ_URLS', [
'auth-forgot' => ['/auth.php', ['m' => 'forgot']],
'auth-reset' => ['/auth.php', ['m' => 'reset', 'u' => '']],
'auth-logout' => ['/auth.php', ['m' => 'logout', 's' => '{logout}']],
+ 'auth-resolve-user' => ['/auth.php', ['m' => 'get_user', 'u' => '']],
'changelog-index' => ['/changelog.php'],
'changelog-change' => ['/changelog.php', ['c' => '']],
@@ -61,6 +62,7 @@ define('MSZ_URLS', [
'user-avatar' => ['/user-assets.php', ['u' => '', 'm' => 'avatar']],
'user-background' => ['/user-assets.php', ['u' => '', 'm' => 'background']],
+ 'user-relation-create' => ['/relations.php', ['u' => '', 'm' => '', 'c' => '{user_relation}']],
'user-relation-none' => ['/relations.php', ['u' => '', 'm' => '[MSZ_USER_RELATION_NONE]', 'c' => '{user_relation}']],
'user-relation-follow' => ['/relations.php', ['u' => '', 'm' => '[MSZ_USER_RELATION_FOLLOW]', 'c' => '{user_relation}']],
@@ -105,6 +107,11 @@ function url(string $name, array $variables = []): string
}
$info = MSZ_URLS[$name];
+
+ if (!is_string($info[0] ?? null)) {
+ return '';
+ }
+
$splitUrl = explode('/', $info[0]);
for ($i = 0; $i < count($splitUrl); $i++) {
@@ -113,10 +120,6 @@ function url(string $name, array $variables = []): string
$url = implode('/', $splitUrl);
- if (!is_string($url)) {
- return '';
- }
-
if (!empty($info[1]) && is_array($info[1])) {
$url .= '?';
diff --git a/templates/_layout/header.twig b/templates/_layout/header.twig
index 429d50cc..ae98d01f 100644
--- a/templates/_layout/header.twig
+++ b/templates/_layout/header.twig
@@ -7,7 +7,7 @@
'menu': [
{
'title': 'Members',
- 'url': url('members-index'),
+ 'url': url('user-list'),
},
{
'title': 'Changelog',