Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance/fix(AP/frontend): 最近追加されたMFMのもろもろを修正 #12420

Merged
merged 9 commits into from
Nov 23, 2023
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
### General
- Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed)
- Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83)
- Fix: MFM `$[unixtime ]` に不正な値を入力した際に発生する各種エラーを修正

### Client
- Enhance: 絵文字のオートコンプリート機能強化 #12364
- fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正
- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367

### Server
- Enhance: MFM `$[ruby ]` が他ソフトウェアと連合されるように
- Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303
- Fix: ロールタイムラインが保存されない問題を修正
- Fix: api.jsonの生成ロジックを改善 #12402
Expand Down
2 changes: 1 addition & 1 deletion locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1856,7 +1856,7 @@ _ago:
weeksAgo: "{n}週間前"
monthsAgo: "{n}ヶ月前"
yearsAgo: "{n}年前"
invalid: "ありません"
invalid: "日時の解析に失敗"

_timeIn:
seconds: "{n}秒後"
Expand Down
79 changes: 68 additions & 11 deletions packages/backend/src/core/MfmService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 } = {
bold: (node) => {
const el = doc.createElement('b');
Expand All @@ -276,17 +282,68 @@ export class MfmService {
},

fn: (node) => {
if (node.props.name === 'unixtime') {
const text = node.children[0]!.type === 'text' ? node.children[0].props.text : '';
const date = new Date(parseInt(text, 10) * 1000);
const el = doc.createElement('time');
el.setAttribute('datetime', date.toISOString());
el.textContent = date.toISOString();
return el;
} else {
const el = doc.createElement('i');
appendChildren(node.children, el);
return el;
switch (node.props.name) {
case 'unixtime': {
const text = node.children[0].type === 'text' ? node.children[0].props.text : '';
try {
const date = new Date(parseInt(text, 10) * 1000);
const el = doc.createElement('time');
el.setAttribute('datetime', date.toISOString());
el.textContent = date.toISOString();
return el;
} catch (err) {
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);
}
}
},

Expand Down
19 changes: 16 additions & 3 deletions packages/frontend/src/components/global/MkTime.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,25 @@ const props = withDefaults(defineProps<{
mode: 'relative',
});

const _time = props.time == null ? NaN :
typeof props.time === 'number' ? props.time :
(props.time instanceof Date ? props.time : new Date(props.time)).getTime();
function getDateSafe(n: Date | string | number) {
try {
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 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());
const ago = $computed(() => (now - _time) / 1000/*ms*/);

Expand Down
Loading