mirror of
https://github.com/paricafe/misskey.git
synced 2024-11-30 21:06:44 -06:00
enhance/fix(AP/frontend): 最近追加されたMFMのもろもろを修正 (#12420)
* (enhance) MFM rubyが連合されるように * Update Changelog * Update Changelog * (fix) unixtimeのフォールバック (AP) * (fix) unixtimeのフォールバック (frontend) * Update Changelog
This commit is contained in:
parent
4a2a44831b
commit
ed6f866a4f
4 changed files with 87 additions and 15 deletions
|
@ -17,6 +17,7 @@
|
||||||
### General
|
### General
|
||||||
- Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed)
|
- Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed)
|
||||||
- Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83)
|
- Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83)
|
||||||
|
- Fix: MFM `$[unixtime ]` に不正な値を入力した際に発生する各種エラーを修正
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Enhance: 絵文字のオートコンプリート機能強化 #12364
|
- Enhance: 絵文字のオートコンプリート機能強化 #12364
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367
|
- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
|
- Enhance: MFM `$[ruby ]` が他ソフトウェアと連合されるように
|
||||||
- Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303
|
- Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303
|
||||||
- Fix: ロールタイムラインが保存されない問題を修正
|
- Fix: ロールタイムラインが保存されない問題を修正
|
||||||
- Fix: api.jsonの生成ロジックを改善 #12402
|
- Fix: api.jsonの生成ロジックを改善 #12402
|
||||||
|
|
|
@ -1856,7 +1856,7 @@ _ago:
|
||||||
weeksAgo: "{n}週間前"
|
weeksAgo: "{n}週間前"
|
||||||
monthsAgo: "{n}ヶ月前"
|
monthsAgo: "{n}ヶ月前"
|
||||||
yearsAgo: "{n}年前"
|
yearsAgo: "{n}年前"
|
||||||
invalid: "ありません"
|
invalid: "日時の解析に失敗"
|
||||||
|
|
||||||
_timeIn:
|
_timeIn:
|
||||||
seconds: "{n}秒後"
|
seconds: "{n}秒後"
|
||||||
|
|
|
@ -250,6 +250,12 @@ export class MfmService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fnDefault(node: mfm.MfmFn) {
|
||||||
|
const el = doc.createElement('i');
|
||||||
|
appendChildren(node.children, el);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
const handlers: { [K in mfm.MfmNode['type']]: (node: mfm.NodeType<K>) => any } = {
|
const handlers: { [K in mfm.MfmNode['type']]: (node: mfm.NodeType<K>) => any } = {
|
||||||
bold: (node) => {
|
bold: (node) => {
|
||||||
const el = doc.createElement('b');
|
const el = doc.createElement('b');
|
||||||
|
@ -276,17 +282,68 @@ export class MfmService {
|
||||||
},
|
},
|
||||||
|
|
||||||
fn: (node) => {
|
fn: (node) => {
|
||||||
if (node.props.name === 'unixtime') {
|
switch (node.props.name) {
|
||||||
const text = node.children[0]!.type === 'text' ? node.children[0].props.text : '';
|
case 'unixtime': {
|
||||||
const date = new Date(parseInt(text, 10) * 1000);
|
const text = node.children[0].type === 'text' ? node.children[0].props.text : '';
|
||||||
const el = doc.createElement('time');
|
try {
|
||||||
el.setAttribute('datetime', date.toISOString());
|
const date = new Date(parseInt(text, 10) * 1000);
|
||||||
el.textContent = date.toISOString();
|
const el = doc.createElement('time');
|
||||||
return el;
|
el.setAttribute('datetime', date.toISOString());
|
||||||
} else {
|
el.textContent = date.toISOString();
|
||||||
const el = doc.createElement('i');
|
return el;
|
||||||
appendChildren(node.children, el);
|
} catch (err) {
|
||||||
return el;
|
return fnDefault(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'ruby': {
|
||||||
|
if (node.children.length === 1) {
|
||||||
|
const child = node.children[0];
|
||||||
|
const text = child.type === 'text' ? child.props.text : '';
|
||||||
|
const rubyEl = doc.createElement('ruby');
|
||||||
|
const rtEl = doc.createElement('rt');
|
||||||
|
|
||||||
|
// ruby未対応のHTMLサニタイザーを通したときにルビが「劉備(りゅうび)」となるようにする
|
||||||
|
const rpStartEl = doc.createElement('rp');
|
||||||
|
rpStartEl.appendChild(doc.createTextNode('('));
|
||||||
|
const rpEndEl = doc.createElement('rp');
|
||||||
|
rpEndEl.appendChild(doc.createTextNode(')'));
|
||||||
|
|
||||||
|
rubyEl.appendChild(doc.createTextNode(text.split(' ')[0]));
|
||||||
|
rtEl.appendChild(doc.createTextNode(text.split(' ')[1]));
|
||||||
|
rubyEl.appendChild(rpStartEl);
|
||||||
|
rubyEl.appendChild(rtEl);
|
||||||
|
rubyEl.appendChild(rpEndEl);
|
||||||
|
return rubyEl;
|
||||||
|
} else {
|
||||||
|
const rt = node.children.at(-1);
|
||||||
|
|
||||||
|
if (!rt) {
|
||||||
|
return fnDefault(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = rt.type === 'text' ? rt.props.text : '';
|
||||||
|
const rubyEl = doc.createElement('ruby');
|
||||||
|
const rtEl = doc.createElement('rt');
|
||||||
|
|
||||||
|
// ruby未対応のHTMLサニタイザーを通したときにルビが「劉備(りゅうび)」となるようにする
|
||||||
|
const rpStartEl = doc.createElement('rp');
|
||||||
|
rpStartEl.appendChild(doc.createTextNode('('));
|
||||||
|
const rpEndEl = doc.createElement('rp');
|
||||||
|
rpEndEl.appendChild(doc.createTextNode(')'));
|
||||||
|
|
||||||
|
appendChildren(node.children.slice(0, node.children.length - 1), rubyEl);
|
||||||
|
rtEl.appendChild(doc.createTextNode(text.trim()));
|
||||||
|
rubyEl.appendChild(rpStartEl);
|
||||||
|
rubyEl.appendChild(rtEl);
|
||||||
|
rubyEl.appendChild(rpEndEl);
|
||||||
|
return rubyEl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return fnDefault(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -28,12 +28,25 @@ const props = withDefaults(defineProps<{
|
||||||
mode: 'relative',
|
mode: 'relative',
|
||||||
});
|
});
|
||||||
|
|
||||||
const _time = props.time == null ? NaN :
|
function getDateSafe(n: Date | string | number) {
|
||||||
typeof props.time === 'number' ? props.time :
|
try {
|
||||||
(props.time instanceof Date ? props.time : new Date(props.time)).getTime();
|
if (n instanceof Date) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
return new Date(n);
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
getTime: () => NaN,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line vue/no-setup-props-destructure
|
||||||
|
const _time = props.time == null ? NaN : getDateSafe(props.time).getTime();
|
||||||
const invalid = Number.isNaN(_time);
|
const invalid = Number.isNaN(_time);
|
||||||
const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;
|
const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;
|
||||||
|
|
||||||
|
// eslint-disable-next-line vue/no-setup-props-destructure
|
||||||
let now = $ref((props.origin ?? new Date()).getTime());
|
let now = $ref((props.origin ?? new Date()).getTime());
|
||||||
const ago = $computed(() => (now - _time) / 1000/*ms*/);
|
const ago = $computed(() => (now - _time) / 1000/*ms*/);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue