「MediaWiki:Forum.js」の版間の差分

編集の要約なし
編集の要約なし
 
(同じ利用者による、間の7版が非表示)
39行目: 39行目:
                 '.mw-editsection',  // 節編集リンク
                 '.mw-editsection',  // 節編集リンク
                 '#t-permalink',      // 念のため固定リンクも非表示
                 '#t-permalink',      // 念のため固定リンクも非表示
                '#ca-history',      // 「履歴を表示」タブ
                '#t-upload',        // サイドバーのアップロードリンク
             ].join(',') + '{display:none!important;}';
             ].join(',') + '{display:none!important;}';
             document.head.appendChild(editBlockStyle);
             document.head.appendChild(editBlockStyle);
170行目: 172行目:
                 // 匿名ユーザーのみ投稿フォームの上部に表示される
                 // 匿名ユーザーのみ投稿フォームの上部に表示される
                 const anonSettingsHtml = isAnon ? `<details id="f-name-settings" style="margin-bottom:.8em;border:1px solid #ccc;padding:.5em;border-radius:3px;">
                 const anonSettingsHtml = isAnon ? `<details id="f-name-settings" style="margin-bottom:.8em;border:1px solid #ccc;padding:.5em;border-radius:3px;">
<summary style="cursor:pointer;font-weight:bold;user-select:none;">名前・トリップの設定</summary>
<summary style="cursor:pointer;font-weight:bold;user-select:none;">名前・トリップの設定</summary>
<div style="margin-top:.5em;">
<div style="margin-top:.5em;">
   <p style="margin:.2em 0 .5em;font-size:.9em;color:#555;">
   <p style="margin:.2em 0 .5em;font-size:.9em;color:#555;">
207行目: 209行目:
                     deletesummary: 'delete post',
                     deletesummary: 'delete post',
                     deletethreadsummary: 'スレッドの削除',
                     deletethreadsummary: 'スレッドの削除',
                     toppage_css: "<style>.f-sticky>td:first-child>a::before{content:'';background-image:url(https://upload.wikimedia.org/wikipedia/commons/a/a5/OOjs_UI_icon_pushPin.svg);width:.8em;height:.8em;margin-right:.2em;display:inline-block;background-size:.8em}#f-loadmore{display:block;margin-left:auto;margin-right:auto;}</style>",
                     toppage_css: "<style>.f-sticky>td:first-child>a::before{content:'';background-image:url(https://upload.wikimedia.org/wikipedia/commons/a/a5/OOjs_UI_icon_pushPin.svg);width:.8em;height:.8em;margin-right:.2em;display:inline-block;background-size:.8em}#f-loadmore{display:block;margin-left:auto;margin-right:auto;}#f-create-btn-mobile{display:none;margin:1em 0;text-align:right;}@media (max-width:768px){.mw-indicators{display:block!important;}#f-create-btn-mobile{display:block;}}#f-notice{background:#fffacd;border:1px solid #daa520;border-radius:4px;padding:1em;margin:1em 0;font-size:.95em;line-height:1.6;}</style>",
                    toppage_notice: mw.forum.notice ? `<div id="f-notice">${mw.forum.notice}</div>` : '',
                     load_more: '<input type="button" value="もっと読み込む" class="mw-ui-button" id="f-loadmore">',
                     load_more: '<input type="button" value="もっと読み込む" class="mw-ui-button" id="f-loadmore">',
                     create: '<input type="button" class="mw-ui-button mw-ui-progressive" value="スレッドを作成">',
                     create: '<input type="button" class="mw-ui-button mw-ui-progressive" value="スレッドを作成">',
263行目: 266行目:
                         const source = await (await fetch(mw.config.get('wgScript') + `?title=${mw.config.get('wgPageName')}&action=raw`)).text();
                         const source = await (await fetch(mw.config.get('wgScript') + `?title=${mw.config.get('wgPageName')}&action=raw`)).text();
                         const newText = source.replace(new RegExp(`(\\{\\{post\\|(.*?)\\|${postId}\\|(.*?)\\|4=)((.|\n)*?)(}})`), '$1[Deleted]$6');
                         const newText = source.replace(new RegExp(`(\\{\\{post\\|(.*?)\\|${postId}\\|(.*?)\\|4=)((.|\n)*?)(}})`), '$1[Deleted]$6');
                         fetch('/mediawiki/forum-proxy.php', {
                         fetch('/wiki/forum-proxy.php', {
                             method: 'POST',
                             method: 'POST',
                             headers: { 'Content-Type': 'application/json' },
                             headers: { 'Content-Type': 'application/json' },
285行目: 288行目:
                         const threadName = mw.config.get('wgPageName').replace(mw.forum.toppage + '/', '');
                         const threadName = mw.config.get('wgPageName').replace(mw.forum.toppage + '/', '');
                         if (!confirm(`スレッド「${threadName}」を削除しますか?\nこの操作は取り消せません。`)) return;
                         if (!confirm(`スレッド「${threadName}」を削除しますか?\nこの操作は取り消せません。`)) return;
                         fetch('/mediawiki/forum-proxy.php', {
                         fetch('/wiki/forum-proxy.php', {
                             method: 'POST',
                             method: 'POST',
                             headers: { 'Content-Type': 'application/json' },
                             headers: { 'Content-Type': 'application/json' },
397行目: 400行目:
                             const anonParam = isAnon ? '|anon=1' : '';
                             const anonParam = isAnon ? '|anon=1' : '';
                             content += `{{post|${mw.forum.username}|1|{{subst:#timel:Y/m/d H:i:s}}|4=${document.querySelector('#wpTextbox1').value}${anonParam}}}`;
                             content += `{{post|${mw.forum.username}|1|{{subst:#timel:Y/m/d H:i:s}}|4=${document.querySelector('#wpTextbox1').value}${anonParam}}}`;
                             fetch('/mediawiki/forum-proxy.php', {
                             fetch('/wiki/forum-proxy.php', {
                                 method: 'POST',
                                 method: 'POST',
                                 headers: { 'Content-Type': 'application/json' },
                                 headers: { 'Content-Type': 'application/json' },
420行目: 423行目:
                     mc.innerHTML = msg.loading;
                     mc.innerHTML = msg.loading;
                     func.getthreads().then((res) => {
                     func.getthreads().then((res) => {
                         mc.innerHTML = res[0] + msg.toppage_css;
                         mc.innerHTML = msg.toppage_notice + res[0] + msg.toppage_css;
                       
                        // モバイル用の「スレッドを作成」ボタンを追加
                        const mobileBtn = document.createElement('div');
                        mobileBtn.id = 'f-create-btn-mobile';
                        mobileBtn.innerHTML = msg.create;
                        mc.insertBefore(mobileBtn, mc.firstChild);
                        mobileBtn.querySelector('input').onclick = function () {
                            const url = new URL(window.location.href);
                            url.searchParams.set('newthread', '1');
                            location.href = url;
                        };
                       
                         if (res[1]) {
                         if (res[1]) {
                             document.querySelector('#mw-content-text').innerHTML += msg.load_more;
                             document.querySelector('#mw-content-text').innerHTML += msg.load_more;
495行目: 510行目:
                             postBody.appendtext = `\n{{post|${mw.forum.username}|${lp}|{{subst:#timel:Y/m/d H:i:s}}|4=${document.querySelector('#wpTextbox1').value}${document.querySelector('#f-reply-cb').checked ? '|re=' + document.querySelector('#f-reply').value : ''}${anonParam}}}`;
                             postBody.appendtext = `\n{{post|${mw.forum.username}|${lp}|{{subst:#timel:Y/m/d H:i:s}}|4=${document.querySelector('#wpTextbox1').value}${document.querySelector('#f-reply-cb').checked ? '|re=' + document.querySelector('#f-reply').value : ''}${anonParam}}}`;
                         }
                         }
                         fetch('/mediawiki/forum-proxy.php', {
                         fetch('/wiki/forum-proxy.php', {
                             method: 'POST',
                             method: 'POST',
                             headers: { 'Content-Type': 'application/json' },
                             headers: { 'Content-Type': 'application/json' },
546行目: 561行目:
                         });
                         });
                     }
                     }
                    // ========== レスホバープレビュー ==========
                    // >>>N のリンクにマウスを乗せると該当投稿をポップアップ表示する
                    (() => {
                        // ポップアップ用の浮動div(ページに1つだけ作成)
                        const popup = document.createElement('div');
                        popup.id = 'f-hover-popup';
                        popup.style.cssText = [
                            'position:fixed',
                            'z-index:9999',
                            'max-width:480px',
                            'min-width:200px',
                            'background:#fff',
                            'border:2px solid #BBBBBB',
                            'border-radius:3px',
                            'box-shadow:2px 4px 12px rgba(0,0,0,.2)',
                            'pointer-events:none',  // ポップアップ自体はマウスイベントを無視
                            'display:none',
                            'font-size:.9em',
                            'line-height:1.4',
                        ].join(';');
                        document.body.appendChild(popup);
                        let hideTimer = null;
                        const showPopup = (anchorEl, postId) => {
    const target = document.querySelector(`#post-${postId}`);
    if (!target) return;
    // 対象投稿をクローンしてポップアップに表示
    const clone = target.cloneNode(true);
    clone.querySelectorAll('a[href*="fedit"], span[style*="#d33"]').forEach(el => el.remove());
    popup.innerHTML = '';
    popup.appendChild(clone);
    // ポップアップの位置をリンクの近くに配置(モバイル対応)
    const rect = anchorEl.getBoundingClientRect();
    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;
   
    // ポップアップの最大幅を画面幅の90%に制限
    const maxWidth = Math.min(480, viewportWidth * 0.9);
    popup.style.maxWidth = maxWidth + 'px';
   
    // 一度表示して実際の高さを取得
    popup.style.display = 'block';
    popup.style.visibility = 'hidden';
    const popupHeight = popup.offsetHeight;
    popup.style.visibility = 'visible';
   
    // 縦位置:下に余裕があれば下、なければ上
    const spaceBelow = viewportHeight - rect.bottom;
    const top = spaceBelow > popupHeight + 10
        ? rect.bottom + 4
        : Math.max(4, rect.top - popupHeight - 4);
   
    // 横位置:画面からはみ出ないように調整
    let left = rect.left;
    if (left + maxWidth > viewportWidth - 10) {
        left = viewportWidth - maxWidth - 10;
    }
    if (left < 10) {
        left = 10;
    }
   
    popup.style.left = left + 'px';
    popup.style.top = top + 'px';
};
                        const hidePopup = () => {
                            popup.style.display = 'none';
                        };
                        // >>>N リンクにホバーイベントを設定
                        document.querySelectorAll('.f-content a[href^="#post-"]').forEach(link => {
                            const postId = link.getAttribute('href').replace('#post-', '');
                            link.addEventListener('mouseenter', () => {
                                clearTimeout(hideTimer);
                                showPopup(link, postId);
                            });
                            link.addEventListener('mouseleave', () => {
                                // 少し遅延させてチラつきを防ぐ
                                hideTimer = setTimeout(hidePopup, 100);
                            });
                        });
                    })();
                    // ==========================================
                 }
                 }
             } // end startForum
             } // end startForum