From 2b9a5febd7b65c0169be7de9e087f5b50d64b5a7 Mon Sep 17 00:00:00 2001 From: tizerm Date: Thu, 6 Jun 2024 01:11:44 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=E5=89=8D=E5=BE=8C=E3=81=AELTL=E3=82=92?= =?UTF-8?q?=E5=8F=96=E5=BE=97=E6=A9=9F=E8=83=BD=E3=82=92=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?.=20=E3=81=BE=E3=81=A0=E6=9A=AB=E5=AE=9A.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.html | 1 + src/js/mist_main_event.js | 3 ++ src/js/module/class_status.js | 36 ++++++++++++++++++++++++ src/js/module/class_timeline.js | 49 ++++++++++++++++++++++++++++++--- 4 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/index.html b/src/index.html index 9472baa..67288d7 100644 --- a/src/index.html +++ b/src/index.html @@ -315,6 +315,7 @@
返信/引用元
  • ギャラリー
  • +
  • 前後のLTLを取得
  • 編集(Mastodon)
  • 削除
  • diff --git a/src/js/mist_main_event.js b/src/js/mist_main_event.js index 714e152..157937e 100644 --- a/src/js/mist_main_event.js +++ b/src/js/mist_main_event.js @@ -1295,6 +1295,9 @@ $(document).on("click", "#pop_context_menu>.ui_menu ul#__menu_post_open_layout>li", e => Status.TEMPORARY_CONTEXT_STATUS.openScrollableWindow($(e.target).closest("li").attr("name"))) + $(document).on("click", "#pop_context_menu>.ui_menu .__menu_post_open_localtimeline", + e => Status.getStatus($("#pop_context_menu").attr("name")).then(post => post.openLocalTimelineWindow("default"))) + /** * #Event #Contextmenu * 投稿系メニュー: 編集. diff --git a/src/js/module/class_status.js b/src/js/module/class_status.js index 2fb80b7..c1b8265 100644 --- a/src/js/module/class_status.js +++ b/src/js/module/class_status.js @@ -256,6 +256,7 @@ class Status { default: break } + this.host = host // このステータスを一意に決定するためのキーを設定 this.sort_date = new Date(original_date) @@ -1950,6 +1951,41 @@ class Status { scroll_tl.createScrollableTimeline(this.id) } + openLocalTimelineWindow(layout) { + const auth_account = Account.getByDomain(this.host) + let tl_pref = { // タイムライン設定 + "external": true, + "host": this.host, + "platform": this.platform, + "color": auth_account?.pref.acc_color ?? getRandomColor(), + "timeline_type": "local", + "exclude_reblog": false, + "expand_cw": false, + "expand_media": false, + } + const gp_pref = { // グループ設定 + "multi_user": false, + "multi_timeline": false, + "tl_layout": layout + } + switch (this.platform) { + case 'Mastodon': // Mastodon + tl_pref.rest_url = `https://${this.host}/api/v1/timelines/public` + tl_pref.query_param = { 'local': true } + break + case 'Misskey': // Misskey + tl_pref.rest_url = `https://${this.host}/api/notes/local-timeline` + tl_pref.query_param = {} + break + default: + break + } + + // ローカルタイムラインオブジェクトを生成 + const scroll_tl = new Timeline(tl_pref, new Group(gp_pref, null)) + scroll_tl.createLocalTimeline(this.id) + } + // Getter: Electronの通知コンストラクタに送る通知文を生成して返却 get notification() { let title = null diff --git a/src/js/module/class_timeline.js b/src/js/module/class_timeline.js index 6bfc8bd..7b4c44a 100644 --- a/src/js/module/class_timeline.js +++ b/src/js/module/class_timeline.js @@ -41,8 +41,9 @@ class Timeline { * 引数を指定した場合は、指定した投稿よりも前を30件取得する * * @param max_id この投稿よりも前の投稿を取得する起点のID + * @param since_id この投稿よりも後ろの投稿を取得する起点のID */ - async getTimeline(max_id) { + async getTimeline(max_id, since_id) { // 外部サーバーでなくターゲットのアカウントが存在しない場合はreject if (!this.pref.external && !this.target_account) return Promise.reject('account not found.') // クエリパラメータにlimitプロパティを事前に追加(これはMastodonとMisskeyで共通) @@ -55,7 +56,8 @@ class Timeline { // ヘッダにアクセストークンをセット(認証済みの場合) let header = {} if (!this.pref.external) header = { "Authorization": `Bearer ${this.target_account.pref.access_token}` } - if (max_id) query_param.max_id = max_id // ページ送りの場合はID指定 + if (max_id) query_param.max_id = max_id + if (since_id) query_param.min_id = since_id // REST APIで最新TLを30件取得、する処理をプロミスとして格納 response = await $.ajax({ type: "GET", @@ -64,11 +66,14 @@ class Timeline { headers: header, data: query_param }) + // Mastodonの場合逆順にする + if (since_id) response = response.reverse() break case 'Misskey': // Misskey // クエリパラメータにアクセストークンをセット(認証済みの場合) if (!this.pref.external) query_param.i = this.target_account.pref.access_token - if (max_id) query_param.untilId = max_id // ページ送りの場合はID指定 + if (max_id) query_param.untilId = max_id + if (since_id) query_param.sinceId = since_id // REST APIで最新TLを30件取得、する処理をプロミスとして格納 response = await $.ajax({ type: "POST", @@ -184,7 +189,7 @@ class Timeline { if (!this.reload_timer_id) clearInterval(this.reload_timer_id) // 実行中の場合は一旦削除 this.reload_timer_id = setInterval(() => (async () => { // 最新のタイムラインを取得 - const recent = await this.getTimeline(null) + const recent = await this.getTimeline() // 逆から順にタイムラインに追加 recent.reverse().forEach(post => this.parent_group.prepend(post)) })(), this.pref.reload_span * 60000) @@ -321,6 +326,42 @@ class Timeline { })) } + createLocalTimeline(id) { + this.createScrollableWindow(id, (tl, ref_id, window_key) => { + $(`#${window_key}>.timeline>ul`).append("
  • 起点
  • ") + tl.getTimeline(ref_id).then(body => { // 下方向のローダーを生成 + // ロード画面を削除 + $(`#${window_key}>.timeline>.col_loading`).remove() + createScrollLoader({ // スクロールローダーを生成 + data: body, + target: $(`#${window_key}>.timeline>ul`), + bind: (data, target) => { // ステータスマップに挿入して投稿をバインド + data.forEach(p => tl.ref_group.addStatus(p, () => target.append(p.timeline_element))) + // max_idとして取得データの最終IDを指定 + return data.pop()?.id + }, + load: async max_id => tl.getTimeline(max_id) + }) + }) + tl.getTimeline(null, ref_id).then(body => { // 上方向のローダーを生成 + const target = $(`#${window_key}>.timeline>ul`) + body.forEach(p => tl.ref_group.addStatus(p, () => target.prepend(p.timeline_element))) + /* + createScrollLoader({ // スクロールローダーを生成 + data: body, + target: $(`#${window_key}>.timeline>ul`), + bind: (data, target) => { // ステータスマップに挿入して投稿をバインド + data.forEach(p => tl.ref_group.addStatus(p, () => target.append(p.timeline_element))) + // max_idとして取得データの最終IDを指定 + return data.pop()?.id + }, + load: async max_id => tl.getTimeline(max_id) + })//*/ + }) + }) + + } + /** * #StaticMethod * ローカルにキャッシュされているタイムラインウィンドウオブジェクトを取得する. From 9d0a78a976aa2cdb82117bf798def0e3cf326729 Mon Sep 17 00:00:00 2001 From: tizerm Date: Sat, 8 Jun 2024 00:47:21 +0900 Subject: [PATCH 02/11] =?UTF-8?q?=E5=A4=96=E9=83=A8=E3=82=BF=E3=82=A4?= =?UTF-8?q?=E3=83=A0=E3=83=A9=E3=82=A4=E3=83=B3=E3=82=A6=E3=82=A3=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=82=A6=E3=82=92=E4=B8=8A=E4=B8=8B=E4=B8=A1=E6=96=B9?= =?UTF-8?q?=E5=90=91=E3=81=AB=E3=83=AD=E3=83=BC=E3=83=89=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E3=81=AB=E4=BF=AE=E6=AD=A3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/mist_timeline.css | 23 +++++++++++++ src/index.html | 11 +++++- src/js/mist_main_event.js | 5 +-- src/js/mist_ui.js | 57 ++++++++++++++++++++++++++++++ src/js/mist_utils.js | 35 ------------------- src/js/module/class_status.js | 10 ++++-- src/js/module/class_timeline.js | 61 ++++++++++++++++----------------- 7 files changed, 130 insertions(+), 72 deletions(-) diff --git a/src/css/mist_timeline.css b/src/css/mist_timeline.css index 0a1d69c..7008099 100644 --- a/src/css/mist_timeline.css +++ b/src/css/mist_timeline.css @@ -1085,6 +1085,29 @@ background-repeat: no-repeat; height: 32px; } + > li.__on_top_loader { + background-image: url("../resources/ic_top.png"); + background-position: center left; + background-repeat: no-repeat; + background-color: #415687; + border-radius: 16px; + font-size: 16px; + font-weight: bold; + text-align: center; + padding: 4px 0px; + &:hover { + background-color: #3562cc; + cursor: pointer; + } + &.loader_loading { + background-image: url("../resources/illust/ani_wait.png"); + background-position: center center; + height: 32px; + } + } + > li.mark_target_post:not(.chat_timeline), > li.mark_target_post.chat_timeline>.content { + border: solid 2px #cccccc; + } > li>.label_head.label_reblog { background-position: center right; diff --git a/src/index.html b/src/index.html index 67288d7..1889cc7 100644 --- a/src/index.html +++ b/src/index.html @@ -315,7 +315,16 @@
    返信/引用元
  • ギャラリー
  • -
  • 前後のLTLを取得
  • +
  • 前後のLTLを取得
    +
      +
    • ノーマル
    • +
    • ノーマル2
    • +
    • チャット
    • +
    • リスト
    • +
    • メディア
    • +
    • ギャラリー
    • +
    +
  • 編集(Mastodon)
  • 削除
  • diff --git a/src/js/mist_main_event.js b/src/js/mist_main_event.js index 157937e..33e1f3d 100644 --- a/src/js/mist_main_event.js +++ b/src/js/mist_main_event.js @@ -1295,8 +1295,9 @@ $(document).on("click", "#pop_context_menu>.ui_menu ul#__menu_post_open_layout>li", e => Status.TEMPORARY_CONTEXT_STATUS.openScrollableWindow($(e.target).closest("li").attr("name"))) - $(document).on("click", "#pop_context_menu>.ui_menu .__menu_post_open_localtimeline", - e => Status.getStatus($("#pop_context_menu").attr("name")).then(post => post.openLocalTimelineWindow("default"))) + $(document).on("click", "#pop_context_menu>.ui_menu ul#__menu_post_open_localtimeline>li", + e => Status.getStatus($("#pop_context_menu").attr("name")) + .then(post => post.openLocalTimelineWindow($(e.target).closest("li").attr("name")))) /** * #Event #Contextmenu diff --git a/src/js/mist_ui.js b/src/js/mist_ui.js index b2b11a2..2a861e4 100644 --- a/src/js/mist_ui.js +++ b/src/js/mist_ui.js @@ -251,3 +251,60 @@ function getRandomColor() { const index = Math.floor(Math.random() * color_palette.length) return color_palette[index] } + +/** + * #Util + * 要素を表示したら続きを読み込むスクロールローダーを生成する + * + * @param arg パラメータオブジェクト + */ +function createScrollLoader(arg) { + // 最初に取得したデータをもとにデータのバインド処理を行う(返り値はページング用max_id) + const max_id = arg.bind(arg.data, arg.target) + if (!max_id) return // max_idが空の場合はデータ終端として終了 + + // Loader Elementを生成 + arg.target.append(`
  •  
  • `) + + // Intersection Observerを生成 + const observer = new IntersectionObserver((entries, obs) => (async () => { + const e = entries[0] + if (!e.isIntersecting) return // 見えていないときは実行しない + console.log('ローダー表示: ' + max_id) + // Loaderを一旦解除してロード画面に変更 + obs.disconnect() + $(e.target).css('background-image', 'url("resources/illust/ani_wait.png")') + + // Loaderのmax_idを使ってデータ取得処理を実行 + arg.data = await arg.load(max_id) + // Loaderを削除して再帰的にLoader生成関数を実行 + $(e.target).remove() + createScrollLoader(arg) + })(), { + root: arg.target.get(0), + rootMargin: "0px", + threshold: 1.0, + }) + observer.observe(arg.target.find(".__scroll_loader").get(0)) +} + +function createTopLoader(arg) { + // 最初に取得したデータをもとにデータのバインド処理を行う(返り値はページング用since_id) + const since_id = arg.bind(arg.data, arg.target) + if (!since_id) return // since_idが空の場合はデータ終端として終了 + + // Loader Elementを生成してクリックイベントを生成(一回だけ実行) + arg.target.prepend(`
  • 続きをロード
  • `) + arg.target.find(".__on_top_loader").get(0).addEventListener('click', e => (async () => { + console.log('トップリロード: ' + since_id) + // ボタンをロード画面に変更 + $(e.target).empty().addClass('loader_loading') + + // Loaderのsince_idを使ってデータ取得処理を実行 + arg.data = await arg.load(since_id) + // Loaderを削除して再帰的にLoader生成関数を実行 + $(e.target).remove() + createTopLoader(arg) + })(), { once: true }) +} + diff --git a/src/js/mist_utils.js b/src/js/mist_utils.js index efa8633..b31f210 100644 --- a/src/js/mist_utils.js +++ b/src/js/mist_utils.js @@ -120,38 +120,3 @@ function shiftArray(array, obj, limit) { return true } -/** - * #Util - * 要素を表示したら続きを読み込むスクロールローダーを生成する - * - * @param arg パラメータオブジェクト - */ -function createScrollLoader(arg) { - // 最初に取得したデータをもとにデータのバインド処理を行う(返り値はページング用max_id) - const max_id = arg.bind(arg.data, arg.target) - if (!max_id) return // max_idが空の場合はデータ終端として終了 - - // Loader Elementを生成 - arg.target.append(`
  •  
  • `) - - // Intersection Observerを生成 - const observer = new IntersectionObserver((entries, obs) => (async () => { - const e = entries[0] - if (!e.isIntersecting) return // 見えていないときは実行しない - console.log('ローダー表示: ' + max_id) - // Loaderを一旦解除してロード画面に変更 - obs.disconnect() - $(e.target).css('background-image', 'url("resources/illust/ani_wait.png")') - - // Loaderのmax_idを使ってデータ取得処理を実行 - arg.data = await arg.load(max_id) - // Loaderを削除して再帰的にLoader生成関数を実行 - $(e.target).remove() - createScrollLoader(arg) - })(), { - root: arg.target.get(0), - rootMargin: "0px", - threshold: 1.0, - }) - observer.observe(arg.target.find(".__scroll_loader").get(0)) -} diff --git a/src/js/module/class_status.js b/src/js/module/class_status.js index c1b8265..997c984 100644 --- a/src/js/module/class_status.js +++ b/src/js/module/class_status.js @@ -1948,13 +1948,14 @@ class Status { this.from_timeline?.pref, new Group(structuredClone(this.from_group?.pref), null)) // タイムラインレイアウトが指定されている場合は変更 if (layout) scroll_tl.ref_group.pref.tl_layout = layout - scroll_tl.createScrollableTimeline(this.id) + scroll_tl.createLoadableTimeline(this) } openLocalTimelineWindow(layout) { const auth_account = Account.getByDomain(this.host) let tl_pref = { // タイムライン設定 - "external": true, + "key_address": auth_account?.full_address, + "external": auth_account ? false : true, "host": this.host, "platform": this.platform, "color": auth_account?.pref.acc_color ?? getRandomColor(), @@ -1983,7 +1984,10 @@ class Status { // ローカルタイムラインオブジェクトを生成 const scroll_tl = new Timeline(tl_pref, new Group(gp_pref, null)) - scroll_tl.createLocalTimeline(this.id) + this.from_timeline = scroll_tl + this.from_account = auth_account + this.detail_flg = false + scroll_tl.createLoadableTimeline(this) } // Getter: Electronの通知コンストラクタに送る通知文を生成して返却 diff --git a/src/js/module/class_timeline.js b/src/js/module/class_timeline.js index 7b4c44a..9206f39 100644 --- a/src/js/module/class_timeline.js +++ b/src/js/module/class_timeline.js @@ -326,40 +326,39 @@ class Timeline { })) } - createLocalTimeline(id) { - this.createScrollableWindow(id, (tl, ref_id, window_key) => { - $(`#${window_key}>.timeline>ul`).append("
  • 起点
  • ") - tl.getTimeline(ref_id).then(body => { // 下方向のローダーを生成 - // ロード画面を削除 + createLoadableTimeline(post) { + this.createScrollableWindow(post.id, (tl, ref_id, window_key) => { + // 起点の投稿を表示して変数にマークする + post.getLayoutElement(tl.ref_group.pref.tl_layout) + .closest('li').addClass('mark_target_post').appendTo(`#${window_key}>.timeline>ul`) + const mark_elm = $(`#${window_key}>.timeline>ul>li:first-child`).get(0) + + // 上下方向のローダーを生成 + Promise.all([tl.getTimeline(ref_id).then(body => createScrollLoader({ // 下方向のローダーを生成 + data: body, + target: $(`#${window_key}>.timeline>ul`), + bind: (data, target) => { // ステータスマップに挿入して投稿をバインド + data.forEach(p => tl.ref_group.addStatus(p, () => target.append(p.timeline_element))) + // max_idとして取得データの最終IDを指定 + return data.pop()?.id + }, + load: async max_id => tl.getTimeline(max_id) + })), tl.getTimeline(null, ref_id).then(body => createTopLoader({ // 上方向のローダーを生成 + data: body, + target: $(`#${window_key}>.timeline>ul`), + bind: (data, target) => { // ステータスマップに挿入して投稿をバインド + const first_elm = target.find('li:first-child').get(0) + data.forEach(p => tl.ref_group.addStatus(p, () => target.prepend(p.timeline_element))) + first_elm.scrollIntoView({ block: 'center' }) + // since_idとして取得データの最終IDを指定 + return data.pop()?.id + }, + load: async since_id => tl.getTimeline(null, since_id) + }))]).then(() => { // 両方ロードが終わったらロード画面を削除してマークした要素にスクロールを合わせる $(`#${window_key}>.timeline>.col_loading`).remove() - createScrollLoader({ // スクロールローダーを生成 - data: body, - target: $(`#${window_key}>.timeline>ul`), - bind: (data, target) => { // ステータスマップに挿入して投稿をバインド - data.forEach(p => tl.ref_group.addStatus(p, () => target.append(p.timeline_element))) - // max_idとして取得データの最終IDを指定 - return data.pop()?.id - }, - load: async max_id => tl.getTimeline(max_id) - }) - }) - tl.getTimeline(null, ref_id).then(body => { // 上方向のローダーを生成 - const target = $(`#${window_key}>.timeline>ul`) - body.forEach(p => tl.ref_group.addStatus(p, () => target.prepend(p.timeline_element))) - /* - createScrollLoader({ // スクロールローダーを生成 - data: body, - target: $(`#${window_key}>.timeline>ul`), - bind: (data, target) => { // ステータスマップに挿入して投稿をバインド - data.forEach(p => tl.ref_group.addStatus(p, () => target.append(p.timeline_element))) - // max_idとして取得データの最終IDを指定 - return data.pop()?.id - }, - load: async max_id => tl.getTimeline(max_id) - })//*/ + mark_elm.scrollIntoView({ block: 'center' }) }) }) - } /** From 3a92d9458108db2a0f0b44ee9dc1dcf0eb2ebca8 Mon Sep 17 00:00:00 2001 From: tizerm Date: Sun, 9 Jun 2024 00:04:29 +0900 Subject: [PATCH 03/11] =?UTF-8?q?=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC?= =?UTF-8?q?=E3=83=8D=E3=83=BC=E3=83=A0=E3=83=96=E3=83=AD=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=81=AE=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88=E3=82=92?= =?UTF-8?q?=E5=BE=AE=E8=AA=BF=E6=95=B4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/mist_timeline.css | 67 ++++++++++++++++----------------- src/js/module/class_status.js | 33 ++++++++-------- src/js/module/class_timeline.js | 25 ++---------- 3 files changed, 55 insertions(+), 70 deletions(-) diff --git a/src/css/mist_timeline.css b/src/css/mist_timeline.css index 7008099..a3e2405 100644 --- a/src/css/mist_timeline.css +++ b/src/css/mist_timeline.css @@ -286,7 +286,7 @@ /*=== User Info ======================================================================*/ > .user { position: relative; - margin: -2px -4px 0px; + margin: -2px -8px 0px; > .usericon { border-radius: 12px; @@ -294,37 +294,38 @@ height: 48px; cursor: pointer; } - > .username { + > .name_info { position: absolute; - left: 60px; - top: 2px; + top: 0px; + left: 58px; + width: calc(100% - 60px); + } + .username { color: #ffffff; font-size: 18px; font-weight: bold; margin: 0px; - width: calc(100% - 60px); + width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } - > .userid { - position: absolute; - left: 60px; - top: 28px; + .userid { display: block; font-family: Arial, "メイリオ", sans-selif; color: #bbbbbb; font-size: 14px; - width: calc(100% - 60px); + width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; > a { text-decoration: underline; + color: #b5a5ab; cursor: pointer; &:hover { text-decoration: none; - color: #eeeeee; + color: #dddddd; } } } @@ -337,12 +338,11 @@ /*=== User Info (Normal2 Layout) =================================================*/ &.prof_normal2 { - position: absolute; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; width: calc(100% - 16px); - margin: -4px -6px 2px; + margin: -4px -6px 4px; > .usericon { border-radius: 12px; width: 24px; @@ -350,17 +350,22 @@ display: inline-block; vertical-align: text-bottom; } - > .username { - position: static; - font-size: 13px; - font-weight: bold; - display: inline; - > .inline_emoji { height: 18px; } - } - > .userid { - position: static; - display: inline; - font-size: 12px; + > .name_info { + position: absolute; + top: 0px; + left: 28px; + > .username { + position: static; + font-size: 13px; + font-weight: bold; + display: inline; + > .inline_emoji { height: 18px; } + } + > .userid { + position: static; + display: inline; + font-size: 13px; + } } } } @@ -396,8 +401,6 @@ overflow-wrap: break-word; } } - > .prof_normal2+.content { margin-top: 24px; } - &:has(.label_head)>.prof_normal2+.content { margin-top: 30px; } /*=== Reaction Emoji Info ============================================================*/ > .reaction_emoji { @@ -949,20 +952,16 @@ font-size: 11px; } > .user { - margin: 0px 8px; + margin: 0px 6px; > .usericon { border-radius: 18px; width: 36px; height: 36px; } - > .username, > .userid { font-size: 13px; } - > .username { - left: 48px; - top: 1px; - } - > .userid { + > .name_info { left: 48px; - top: 20px; + width: calc(100% - 48px); + > .username, > .userid { font-size: 13px; } } } > .content { diff --git a/src/js/module/class_status.js b/src/js/module/class_status.js index 997c984..5b2e2d5 100644 --- a/src/js/module/class_status.js +++ b/src/js/module/class_status.js @@ -720,6 +720,7 @@ class Status { html += `
    +
    `; switch (Preference.GENERAL_PREFERENCE.normal_name_format) { case 'both_prename': // ユーザーネーム+ユーザーID html += ` @@ -753,16 +754,18 @@ class Status { default: break } - html += '
    ' + html += '
    ' } else html /* ノーマルレイアウトの場合 */ += ` ` } @@ -1270,14 +1273,14 @@ class Status { html /* ユーザーアカウント情報 */ += `
    -

    ${target_emojis.replace(this.user.username)}

    - - - @${this.user.id} - - - ` - html += ` +
    +

    ${target_emojis.replace(this.user.username)}

    + + + @${this.user.id} + + +
    ` // 本文よりも先にメディアを表示 diff --git a/src/js/module/class_timeline.js b/src/js/module/class_timeline.js index 9206f39..8ed5f9b 100644 --- a/src/js/module/class_timeline.js +++ b/src/js/module/class_timeline.js @@ -305,32 +305,15 @@ class Timeline { /** * #Method - * 対象の投稿IDからこのタイムラインの設定で遡りウィンドウを生成 + * 対象の投稿IDからこのタイムラインの設定で外部タイムラインウィンドウを生成 * - * @param id 起点にする投稿ID + * @param post 取得の起点にするStatusオブジェクト */ - createScrollableTimeline(id) { - this.createScrollableWindow(id, (tl, ref_id, window_key) => tl.getTimeline(ref_id).then(body => { - // ロード画面を削除 - $(`#${window_key}>.timeline>.col_loading`).remove() - createScrollLoader({ // スクロールローダーを生成 - data: body, - target: $(`#${window_key}>.timeline>ul`), - bind: (data, target) => { // ステータスマップに挿入して投稿をバインド - data.forEach(p => tl.ref_group.addStatus(p, () => target.append(p.timeline_element))) - // max_idとして取得データの最終IDを指定 - return data.pop()?.id - }, - load: async max_id => tl.getTimeline(max_id) - }) - })) - } - createLoadableTimeline(post) { this.createScrollableWindow(post.id, (tl, ref_id, window_key) => { // 起点の投稿を表示して変数にマークする - post.getLayoutElement(tl.ref_group.pref.tl_layout) - .closest('li').addClass('mark_target_post').appendTo(`#${window_key}>.timeline>ul`) + tl.ref_group.addStatus(post, () => post.getLayoutElement(tl.ref_group.pref.tl_layout) + .closest('li').addClass('mark_target_post').appendTo(`#${window_key}>.timeline>ul`)) const mark_elm = $(`#${window_key}>.timeline>ul>li:first-child`).get(0) // 上下方向のローダーを生成 From 1805dde5fd6400aaa70cccfc82e84251cfd08c65 Mon Sep 17 00:00:00 2001 From: tizerm Date: Tue, 11 Jun 2024 00:37:03 +0900 Subject: [PATCH 04/11] =?UTF-8?q?=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6?= =?UTF-8?q?=E3=83=88=E5=BE=AE=E4=BF=AE=E6=AD=A3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/help/help_main.html | 2 +- src/js/module/class_user.js | 18 ++++++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index e0e1193..c884844 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Mistdon", - "version": "1.2.2", + "version": "1.3.0a", "description": "The integrated client application of Mastodon and Misskey.", "main": "main.js", "scripts": { diff --git a/src/help/help_main.html b/src/help/help_main.html index 369c345..acaebf8 100644 --- a/src/help/help_main.html +++ b/src/help/help_main.html @@ -1489,7 +1489,7 @@

    設定ファイルの場所について

    Mistdonについて

    -
    Current Version: 1.2.2 (2024/06/02)
    +
    Current Version: 1.3.0a (2024/06/09)

    Mistdonは、MastodonとMisskeyの統合Fediverseクライアントです。
    OSSですが基本的にはぜるま(@tizerm@mofu.kemo.no)(@tizerm@misskey.dev)が主導になって開発を行っています(というかコントリビューターは今のところいない……)。
    diff --git a/src/js/module/class_user.js b/src/js/module/class_user.js index ed77ba1..d9cc4e8 100644 --- a/src/js/module/class_user.js +++ b/src/js/module/class_user.js @@ -279,8 +279,10 @@ class User { html /* ユーザーアカウント情報 */ += `

    -

    ${target_emojis.replace(this.username)}

    - ${this.full_address} +
    +

    ${target_emojis.replace(this.username)}

    + ${this.full_address} +
    ` let bookmarks = '' let instance = '' @@ -376,8 +378,10 @@ class User { html /* ユーザーアカウント情報 */ += `
    -

    ${target_emojis.replace(this.username)}

    - ${this.full_address} +
    +

    ${target_emojis.replace(this.username)}

    + ${this.full_address} +
    ` switch (this.platform) { case 'Mastodon': // Mastodon @@ -421,8 +425,10 @@ class User {
  • -

    ${this.username}

    - ${this.full_address} +
    +

    ${this.username}

    + ${this.full_address} +
  • `)) From 8f7f31aff7951af7dd1bd0ba72c78bbd9db36bac Mon Sep 17 00:00:00 2001 From: tizerm Date: Sat, 22 Jun 2024 03:07:10 +0900 Subject: [PATCH 05/11] =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=A0=E3=83=A9?= =?UTF-8?q?=E3=82=A4=E3=83=B3=E3=81=AB=E3=82=A4=E3=83=B3=E3=83=97=E3=83=AC?= =?UTF-8?q?=E3=83=83=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=BB=E3=82=AF=E3=82=B7?= =?UTF-8?q?=E3=83=A7=E3=83=B3=E3=82=92=E8=BF=BD=E5=8A=A0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/mist_main.css | 2 +- src/css/mist_preference.css | 2 +- src/css/mist_timeline.css | 61 ++++++++------ src/js/module/class_status.js | 154 +++++++++++++++++++--------------- 4 files changed, 124 insertions(+), 95 deletions(-) diff --git a/src/css/mist_main.css b/src/css/mist_main.css index 68a8077..d80e933 100644 --- a/src/css/mist_main.css +++ b/src/css/mist_main.css @@ -837,7 +837,7 @@ background-image: url("../resources/ic_reblog.png"); } &.impress_fav { - background-color: #a8880a; + background-color: #825e1b; background-image: url("../resources/ic_favorite.png"); } } diff --git a/src/css/mist_preference.css b/src/css/mist_preference.css index bc5cde7..54114e1 100644 --- a/src/css/mist_preference.css +++ b/src/css/mist_preference.css @@ -235,7 +235,7 @@ &.default { background-color: #3562cc; } &.btrn { background-color: #408a08; } &.media { background-color: #cc355d; } - &.notification { background-color: #a8880a; } + &.notification { background-color: #825e1b; } } & button.__on_layout_close { width: 100%; } } diff --git a/src/css/mist_timeline.css b/src/css/mist_timeline.css index a3e2405..04c58d2 100644 --- a/src/css/mist_timeline.css +++ b/src/css/mist_timeline.css @@ -574,12 +574,25 @@ font-size: 18px; font-weight: bold; text-align: right; - &.count_reblog { background-image: url("../resources/ic_reblog.png"); } - &.count_fav { background-image: url("../resources/ic_favorite.png"); } - &.count_reaction_total { background-image: url("../resources/ic_emoji.png"); } } } + /*=== Impressions Info ===============================================================*/ + > .impressions { + background-color: rgba(31,31,31,0.683); + border-radius: 8px; + > .counter { + display: inline-block; + border-radius: 12px; + padding: 3px 8px 3px 30px; + background-position: center left; + background-repeat: no-repeat; + background-size: 24px 24px; + font-family: Arial, "メイリオ", sans-selif; + } + > .reaction_section { display: inline; } + } + /*=== Detail Info ====================================================================*/ > .detail_info { margin: 6px 8px; @@ -642,14 +655,7 @@ cursor: pointer; } } - .counter { width: calc(33% - 48px); } - .count_post { background-image: url("../resources/ic_rpl.png"); } - .count_follow { background-image: url("../resources/ic_cnt_flw.png"); } - .count_follower { background-image: url("../resources/ic_cnt_flwr.png"); } - .count_reply { background-image: url("../resources/ic_rpl.png"); } - .count_reblog { background-image: url("../resources/ic_reblog.png"); } - .count_fav { background-image: url("../resources/ic_favorite.png"); } - .count_reaction_total { background-image: url("../resources/ic_emoji.png"); } + .counter { width: calc(33% - 48px); } .count_reaction { background-color: rgba(0,172,255,0.2); padding-right: 8px; @@ -1105,7 +1111,7 @@ } } > li.mark_target_post:not(.chat_timeline), > li.mark_target_post.chat_timeline>.content { - border: solid 2px #cccccc; + background-color: #415687; } > li>.label_head.label_reblog { @@ -1130,18 +1136,25 @@ /*=== General Timeline Preference ================================================================*/ -.label_reply { background-color: #cc355d; } -.label_reblog { background-color: #408a08; } -.label_favorite { background-color: #a8880a; } -.label_postcount { background-color: #606060; } -.label_follow { background-color: #3562cc; } -.label_follower { background-color: #cc6a35; } -.label_bookmark { background-color: #c10000; } -.label_cw { background-color: #8c720b; } -.label_sensitive { background-color: #a10000; } -.label_limitover { background-color: #0b638c; } -.label_private { background-color: #bbbbbb; color: #333333; } -.cw_content { display: none; } +.label_reply { background-color: #cc355d; } +.label_reblog { background-color: #408a08; } +.label_favorite { background-color: #825e1b; } +.label_postcount { background-color: #606060; } +.label_follow { background-color: #3562cc; } +.label_follower { background-color: #cc6a35; } +.label_bookmark { background-color: #c10000; } +.label_cw { background-color: #8c720b; } +.label_sensitive { background-color: #a10000; } +.label_limitover { background-color: #0b638c; } +.label_private { background-color: #bbbbbb; color: #333333; } +.cw_content { display: none; } +.count_post { background-image: url("../resources/ic_rpl.png"); } +.count_follow { background-image: url("../resources/ic_cnt_flw.png"); } +.count_follower { background-image: url("../resources/ic_cnt_flwr.png"); } +.count_reply { background-image: url("../resources/ic_rpl.png"); } +.count_reblog { background-image: url("../resources/ic_reblog.png"); } +.count_fav { background-image: url("../resources/ic_favorite.png"); } +.count_reaction_total { background-image: url("../resources/ic_emoji.png"); } /*=== Profile Column Layout ======================================================================*/ diff --git a/src/js/module/class_status.js b/src/js/module/class_status.js index 5b2e2d5..856ba16 100644 --- a/src/js/module/class_status.js +++ b/src/js/module/class_status.js @@ -242,7 +242,7 @@ class Status { this.count_reply = data.repliesCount this.count_reblog = data.renoteCount // リアクションがある場合はリアクション一覧をリスト化する - if ((this.detail_flg || this.notif_type == 'reaction' || this.notif_type == 'renote') && data.reactions) { + if (data.reactions) { const reactions = [] Object.keys(data.reactions).forEach(key => reactions.push({ shortcode: key, @@ -822,30 +822,10 @@ class Status { } else alias = this.reaction_emoji // Unicode絵文字はそのまま渡す html += `
    ${alias}
    ` } - if (this.medias.length > 0) { // 添付メディア(現状は画像のみ) + if (this.medias.length > 0) { // 添付メディア const img_class = this.medias.length > 4 ? 'img_grid_16' : 'img_grid_4' - html += '
    ' - if (this.sensitive) html /* 閲覧注意 */ += ` - 閲覧注意の画像があります -
    - `; else html += '
    ' - // アスペクト比をリンクオプションとして設定 - this.medias.forEach(media => { - if (media.type == 'audio') html /* 音声ファイル(サムネなしで直接埋め込む) */+= ` - - `; else html /* 画像か動画ファイル(サムネから拡大表示) */ += ` - - - - ` - }) - html += ` -
    -
    - ` + html += this.bindMediaSection(img_class) } - // 一部の通知はインプレッション数値を表示する if (Preference.GENERAL_PREFERENCE.enable_notified_impression && ['favourite', 'reblog', 'reaction', 'renote'].includes(this.notif_type)) { @@ -862,7 +842,7 @@ class Status { break } html += '
    ' - } + } else if (!this.detail_flg) html += this.impression_section if (this.detail_flg) { // 詳細表示の場合はリプライ、BTRN、ふぁぼ数を表示 html += '
    ' @@ -957,7 +937,7 @@ class Status { if (this.reply_to) jqelm.closest('li').addClass('replied_post') if (this.reblog) { // BTRNにはクラスをつけて背景をセット jqelm.closest('li').addClass('rebloged_post') - jqelm.find('.label_reblog').css("background-image", `url("${this.reblog_by_icon}")`) + jqelm.find('.label_head.label_reblog').css("background-image", `url("${this.reblog_by_icon}")`) } if (this.profile_post_flg || this.detail_flg) // プロフィールと詳細表示は投稿時刻で色分けする jqelm.find('.post_footer>.created_at').addClass(`from_address ${this.relative_time.color_class}`) @@ -1099,29 +1079,12 @@ class Status { `; else html += `
    ${target_emojis.replace(this.quote.content)}
    ` html += '
    ' } - if (this.medias.length > 0) { // 添付メディア(現状は画像のみ) + if (this.medias.length > 0) { // 添付メディア const img_class = this.medias.length > 4 ? 'img_grid_64' : 'img_grid_16' - html += '
    ' - if (this.sensitive) html /* 閲覧注意 */ += ` - 閲覧注意の画像があります -
    - `; else html += '
    ' - // アスペクト比をリンクオプションとして設定 - this.medias.forEach(media => { - if (media.type == 'audio') html /* 音声ファイル(サムネなしで直接埋め込む) */+= ` - - `; else html /* 画像か動画ファイル(サムネから拡大表示) */ += ` - - - - ` - }) - html += ` -
    -
    - ` + html += this.bindMediaSection(img_class) } + // インプレッション(反応とリアクション) + html += this.impression_section html += ` ` @@ -1130,7 +1093,10 @@ class Status { const jqelm = $($.parseHTML(html)) jqelm.find('.from_address>div').css("background-color", `#${this.account_color}`) jqelm.find('.from_address>.from_auth_user').css("background-image", `url("${this.from_account?.pref.avatar_url}")`) - jqelm.find('.label_reblog').css("background-image", `url("${this.reblog_by_icon}")`) + if (this.reblog) { // BTRNにはクラスをつけて背景をセット + jqelm.closest('li').addClass('rebloged_post') + jqelm.find('.label_head.label_reblog').css("background-image", `url("${this.reblog_by_icon}")`) + } // 期限切れか投票済みの場合は投票ボタンを消して結果を表示する if (this.poll_options && !this.detail_flg && (this.poll_voted || (!this.poll_unlimited && this.poll_expired))) jqelm.find('.post_poll').after(this.poll_graph).remove() @@ -1284,30 +1250,11 @@ class Status {
    ` // 本文よりも先にメディアを表示 - if (this.medias.length > 0) { // 添付メディア(現状は画像のみ) + if (this.medias.length > 0) { // 添付メディア let img_class = 'img_grid_single' if (this.medias.length > 4) img_class = 'img_grid_16' else if (this.medias.length > 1) img_class = 'img_grid_4' - html += '
    ' - if (this.sensitive) html /* 閲覧注意 */ += ` - 閲覧注意の画像があります -
    - `; else html += '
    ' - // アスペクト比をリンクオプションとして設定 - this.medias.forEach(media => { - if (media.type == 'audio') html /* 音声ファイル(サムネなしで直接埋め込む) */+= ` - - `; else html /* 画像か動画ファイル(サムネから拡大表示) */ += ` - - - - ` - }) - html += ` -
    -
    - ` + html += this.bindMediaSection(img_class) } html += `
    @@ -1323,6 +1270,8 @@ class Status {
    ` + // インプレッション(反応とリアクション) + html += this.impression_section html /* 投稿(ステータス)日付 */ += `