@sembokulove (Missing place)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

プルダウンで自作htmlがiframeで表示位置を固定して、読込先のページ数に応じて親ページの高さを変えたいです。

解決したいこと

プルダウンで自作htmlがiframeで表示位置を固定して、iframeを可変サイズとして、それに応じて、親ページの高さを変えたいです。
現状iframeを用いていますが、
これには訳があり、iframeを用いない方法を用いますと、htmlの保護規定によりdom設定しない限り、
直リンクができないしようとなっており、そのための環境設定が難しいためです。
一方、iframe自体のページサイズは大きくできても、
親ファイルのページサイズをiframeによって変更できないのが苦しい実態です。
解決策はないのでしょうか?
例)
Ruby on RailsでQiitaのようなWebアプリをつくっています。
記事を投稿する機能の実装中にエラーが発生しました。
解決方法を教えて下さい。

発生している問題・エラー

出ているエラーメッセージを入力

例)


スクリーンショット 2025-07-29 133116.png

該当するソースコード

<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>5階層プルダウン (HTML完結)</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <style>
        select {
            margin: 5px;
            padding: 8px;
            border: 1px solid #ccc;
            border-radius: 4px;
            font-size: 1rem;
            width: 200px;
        }
    </style>
    <style>
    body {
        margin: 0; /* 追加: bodyの余白をなくす */
        padding: 0; /* 追加: bodyのパディングをなくす */
        /* overflow: hidden; */ /* 今回は親HTMLが延長する方式なので不要、または除去 */
    }
    iframe {
        width: 100vw;
        height: 100vh;
        border: none;
        overflow: hidden;
    }
    </style>
</head>
<body>
    <h1>5階層プルダウンメニュー (HTML完結)</h1>

    <select id="level1">
        <option value="">選択してください</option>
        <option value="JR">JR</option>
        <option value="大手私鉄">大手私鉄</option>
        <option value="高速バスその他">高速バスその他</option>
    </select>

    <select id="level2" disabled>
        <option value="">選択してください</option>
        <option value="新幹線" data-parent="JR">新幹線</option>
        <option value="JR北海道" data-parent="JR">JR北海道</option>
        <option value="JR東日本" data-parent="JR">JR東日本</option>
        <option value="JR東海" data-parent="JR">JR東海</option>
        <option value="JR西日本" data-parent="JR">JR西日本</option>
        <option value="JR四国" data-parent="JR">JR四国</option>
        <option value="JR九州" data-parent="JR">JR九州</option>
    </select>

    <select id="level3" disabled>
        <option value="">選択してください</option>
        <option value="東北・北海道・山形・秋田新幹線" data-parent="新幹線">東北・北海道・山形・秋田新幹線</option>
        <option value="上越・北陸新幹線" data-parent="新幹線">上越・北陸新幹線</option>
        <option value="東海道・山陽新幹線" data-parent="新幹線">東海道・山陽新幹線</option>
        <option value="九州・西九州新幹線" data-parent="新幹線">九州・西九州新幹線</option>
        <option value="北海道地区" data-parent="JR北海道">北海道地区</option>
        <option value="首都圏各線" data-parent="JR東日本">首都圏各線</option>
        <option value="中央本線系統" data-parent="JR東日本">中央本線系統</option>
        <option value="上信越線系統" data-parent="JR東日本">上信越線系統</option>
        <option value="東北地区" data-parent="JR東日本">東北地区</option>
        <option value="東海地区" data-parent="JR東海">東海地区</option>
        <option value="北陸地区" data-parent="JR西日本">北陸地区</option>
        <option value="nagoya" data-parent="aichi">名古屋市</option>
    </select>

    <select id="level4" disabled>
        <option value="">選択してください</option>
        <option value="はやぶさ(現役、新幹線時代)" data-parent="東北・北海道・山形・秋田新幹線">はやぶさ(現役、新幹線時代)</option>
        <option value="はやて(現役)" data-parent="東北・北海道・山形・秋田新幹線">はやて(現役)</option>
        <option value="こまち(現役)" data-parent="東北・北海道・山形・秋田新幹線">こまち(現役)</option>
        <option value="サンダーバード(現役)" data-parent="北陸地区">特急 サンダーバード(現役)</option>
        <option value="しらさぎ(現役)" data-parent="北陸地区">特急 しらさぎ(現役)</option>
        <option value="能登かがり火(現役)" data-parent="北陸地区">特急 能登かがり火(現役)</option>
        <option value="花嫁のれん(現役、臨時列車)" data-parent="北陸地区">特急 花嫁のれん(現役、臨時列車)</option>
        <option value="べるもんた(現役、臨時列車)" data-parent="北陸地区">快速 ベル・モンターユ・エ・メール(べるもんた) (現役、臨時列車)</option>
        <option value="スーパー雷鳥(退役)" data-parent="北陸地区">特急 スーパー雷鳥(退役)</option>
        <option value="雷鳥(退役)" data-parent="北陸地区">特急 雷鳥(退役)</option>
        <option value="白鳥(退役)" data-parent="北陸地区">特急 白鳥(退役)</option>
        <option value="加越(退役)" data-parent="北陸地区">特急 加越(退役)</option>
        <option value="はくたか(退役、在来線時代)" data-parent="北陸地区">特急 はくたか(退役、在来線時代)</option>
        <option value="北越(退役)" data-parent="北陸地区">特急 北越(退役)</option>
        <option value="急行能登(退役)" data-parent="北陸地区">急行 能登(退役)</option>
    </select>

    <select id="level5" disabled>
        <option value="">選択してください</option>
        <optgroup label="19971001ダイヤ改正">
        <option value="19971001現在編成-スーパー雷鳥1001A" data-parent="スーパー雷鳥(退役)" data-url="座席表/JR西日本/19971001現在 スーパー雷鳥1001A 20250728 Mon.html">しらさぎ編成その1</option>
        <option value="19971001現在編成-スーパー雷鳥1002A" data-parent="スーパー雷鳥(退役)" data-url="座席表/JR西日本/19971001現在 スーパー雷鳥1002A 20250728 Mon.html">しらさぎ編成その2パターンA</option>
        <option value="19971001現在編成-雷鳥1001A" data-parent="雷鳥(退役)" data-url="座席表/JR西日本/19971001現在 雷鳥1001A 20250728 Mon.html">しらさぎ編成その1</option>
        <option value="19971001現在編成-雷鳥1002A" data-parent="雷鳥(退役)" data-url="座席表/JR西日本/19971001現在 雷鳥1001B 20250728 Mon.html">しらさぎ編成その2パターンA</option>
    </select>
    <div id="contentDisplay" style="margin-top: 20px;">
        <p>ここに選択されたコンテンツが表示されます。</p>
        <button id="resetSelection">選択を初期化</button>
        <iframe id="dynamicIframe" src=""></iframe>
    </div>
<style>
select {
    margin: 5px;
    padding: 8px;
    border: 1px solid #ccc;
    border-radius: 4px;
    font-size: 1rem;
    width: 200px;
}

body {
    margin: 0;
    padding: 0;
    /* overflow: hidden; */
}

iframe {
    width: 100vw;
    height: 100vh;
    border: none;
    overflow: hidden;
}

iframe {
    border: none;
    display: block;
    margin: 0 auto;
    overflow: hidden;
}
</style>
<script>
$(document).ready(function() {

    /**
     * 次の階層以降のプルダウンをリセットし、無効化、オプションを非表示にする
     * @param {number} startLevel - リセットを開始する階層の番号
     */
    function resetNextLevels(startLevel) {
        for (let i = startLevel; i <= 5; i++) { // 階層の最大値を5に合わせる
            const $currentSelect = $(`#level${i}`);
            $currentSelect.val(''); // 選択をクリア

            // level1 以外は無効化、またはstartLevelが2以上の場合は無効化
            if (i > 1 || startLevel > 1) { // level1は常に有効にする
                $currentSelect.prop('disabled', true);
            } else {
                $currentSelect.prop('disabled', false); // level1は有効のまま
            }

            // level1 以外のオプションを非表示にする(選択してください、以外)
            // i === 1 (level1) の場合は、オプションを非表示にしないようにする
            if (i > 1) {
                $currentSelect.find('option:not([value=""])').hide();
            }
        }
    }

    /**
     * 指定されたプルダウンの関連オプションを表示し、有効化する
     * @param {string} selector - プルダウンのCSSセレクタ (例: '#level2')
     * @param {string} parentValue - 親のプルダウンで選択された値
     */
    function showRelatedOptions(selector, parentValue) {
        const $select = $(selector);
        $select.prop('disabled', false); // プルダウンを有効化

        // 親の値に紐づくオプションを表示
        $select.find(`option[data-parent="${parentValue}"]`).show();
        // 「選択してください」オプションも表示しておく
        $select.find('option[value=""]').show();
    }

    // 初期状態: level2 から level5 までのオプションを全て非表示にし、プルダウンを無効化
    resetNextLevels(2); // level2以降をリセットし無効化

    // 初期ロード時にlevel1を明示的に有効にする(念のため)
    $('#level1').prop('disabled', false);
    // level1の全オプションを表示する(初期状態では非表示になっていないはずだが、念のため)
    $('#level1').find('option').show();


    // --- イベントリスナーの設定 ---

    $('#level1').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(2); // level2以降をリセット
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level2', selectedParent);
        }
    });

    $('#level2').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(3);
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level3', selectedParent);
        }
    });

    $('#level3').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(4);
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level4', selectedParent);
        }
    });

    $('#level4').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(5);
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level5', selectedParent);
        }
    });

    // level5 の変更イベント (iframe表示に変更)
    $('#level5').on('change', function() {
        const selectedOption = $(this).find('option:selected');
        const finalSelectionValue = selectedOption.val();
        const targetUrl = selectedOption.data('url');

        const $dynamicIframe = $('#dynamicIframe');
        const $contentDisplayMessage = $('#contentDisplay p');

        if (targetUrl) {
            $contentDisplayMessage.hide();
            $dynamicIframe.attr('src', targetUrl).show();
            console.log("選択されたURLをiframeに表示:", targetUrl);

            // iframeのロード完了時に高さを調整
            $dynamicIframe.off('load').on('load', function() {
                try {
                    // 同じオリジンのコンテンツのみアクセス可能
                    const iframeContentHeight = this.contentWindow.document.body.scrollHeight;
                    $(this).css('height', iframeContentHeight + 'px');
                    console.log("iframeの高さを調整:", iframeContentHeight + "px");
                } catch (e) {
                    console.warn("iframeのコンテンツにアクセスできません。異なるオリジンである可能性があります。", e);
                    // 異なるオリジンの場合は、固定の高さに戻すか、スクロールを許可するなどの対応
                    $(this).css('height', '100vh'); // あるいは、適切なデフォルト値
                }
            });

        } else {
            $dynamicIframe.attr('src', '').hide();
            $dynamicIframe.css('height', '100vh'); // iframeをクリアしたら元の高さに戻すか、適切なデフォルト値
            $contentDisplayMessage.show();
            console.log("iframe表示クリア");
        }
    });

    // 「選択を初期化」ボタンのクリックイベントリスナー
    $('#resetSelection').on('click', function() {
        resetNextLevels(1); // 全てのレベルをリセット(level1も含む)
        $('#level1').prop('disabled', false); // level1を明示的に有効にする
        $('#level1').find('option').show(); // level1の全オプションを表示
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示
    });
});
</script>
</body>
</html>

スクリーンショット 2025-07-29 133809.png


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>5階層プルダウン (HTML完結)</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <style>
        select {
            margin: 5px;
            padding: 8px;
            border: 1px solid #ccc;
            border-radius: 4px;
            font-size: 1rem;
            width: 200px;
        }
    </style>
    <style>
    body {
        margin: 0; /* 追加: bodyの余白をなくす */
        padding: 0; /* 追加: bodyのパディングをなくす */
        /* overflow: hidden; */ /* 今回は親HTMLが延長する方式なので不要、または除去 */
    }
    iframe {
        width: 100vw;
        height: 100vh;
        border: none;
        overflow: hidden;
    }
    </style>
</head>
<body>
    <h1>5階層プルダウンメニュー (HTML完結)</h1>

    <select id="level1">
        <option value="">選択してください</option>
        <option value="JR">JR</option>
        <option value="大手私鉄">大手私鉄</option>
        <option value="高速バスその他">高速バスその他</option>
    </select>

    <select id="level2" disabled>
        <option value="">選択してください</option>
        <option value="新幹線" data-parent="JR">新幹線</option>
        <option value="JR北海道" data-parent="JR">JR北海道</option>
        <option value="JR東日本" data-parent="JR">JR東日本</option>
        <option value="JR東海" data-parent="JR">JR東海</option>
        <option value="JR西日本" data-parent="JR">JR西日本</option>
        <option value="JR四国" data-parent="JR">JR四国</option>
        <option value="JR九州" data-parent="JR">JR九州</option>
    </select>

    <select id="level3" disabled>
        <option value="">選択してください</option>
        <option value="東北・北海道・山形・秋田新幹線" data-parent="新幹線">東北・北海道・山形・秋田新幹線</option>
        <option value="上越・北陸新幹線" data-parent="新幹線">上越・北陸新幹線</option>
        <option value="東海道・山陽新幹線" data-parent="新幹線">東海道・山陽新幹線</option>
        <option value="九州・西九州新幹線" data-parent="新幹線">九州・西九州新幹線</option>
        <option value="北海道地区" data-parent="JR北海道">北海道地区</option>
        <option value="首都圏各線" data-parent="JR東日本">首都圏各線</option>
        <option value="中央本線系統" data-parent="JR東日本">中央本線系統</option>
        <option value="上信越線系統" data-parent="JR東日本">上信越線系統</option>
        <option value="東北地区" data-parent="JR東日本">東北地区</option>
        <option value="東海地区" data-parent="JR東海">東海地区</option>
        <option value="北陸地区" data-parent="JR西日本">北陸地区</option>
        <option value="nagoya" data-parent="aichi">名古屋市</option>
    </select>

    <select id="level4" disabled>
        <option value="">選択してください</option>
        <option value="">選択してください</option>
        <option value="はやぶさ(現役、新幹線時代)" data-parent="東北・北海道・山形・秋田新幹線">はやぶさ(現役、新幹線時代)</option>
        <option value="はやて(現役)" data-parent="東北・北海道・山形・秋田新幹線">はやて(現役)</option>
        <option value="こまち(現役)" data-parent="東北・北海道・山形・秋田新幹線">こまち(現役)</option>
        <option value="サンダーバード(現役)" data-parent="北陸地区">特急 サンダーバード(現役)</option>
        <option value="しらさぎ(現役)" data-parent="北陸地区">特急 しらさぎ(現役)</option>
        <option value="能登かがり火(現役)" data-parent="北陸地区">特急 能登かがり火(現役)</option>
        <option value="花嫁のれん(現役、臨時列車)" data-parent="北陸地区">特急 花嫁のれん(現役、臨時列車)</option>
        <option value="べるもんた(現役、臨時列車)" data-parent="北陸地区">快速 ベル・モンターユ・エ・メール(べるもんた) (現役、臨時列車)</option>
        <option value="スーパー雷鳥(退役)" data-parent="北陸地区">特急 スーパー雷鳥(退役)</option>
        <option value="雷鳥(退役)" data-parent="北陸地区">特急 雷鳥(退役)</option>
        <option value="白鳥(退役)" data-parent="北陸地区">特急 白鳥(退役)</option>
        <option value="加越(退役)" data-parent="北陸地区">特急 加越(退役)</option>
        <option value="はくたか(退役、在来線時代)" data-parent="北陸地区">特急 はくたか(退役、在来線時代)</option>
        <option value="北越(退役)" data-parent="北陸地区">特急 北越(退役)</option>
        <option value="急行能登(退役)" data-parent="北陸地区">急行 能登(退役)</option>
    </select>

    <select id="level5" disabled>
        <option value="">選択してください</option>
        <optgroup label="19971001ダイヤ改正">
        <option value="19971001現在編成-スーパー雷鳥1001A" data-parent="スーパー雷鳥(退役)" data-url="座席表/JR西日本/19971001現在 スーパー雷鳥1001A 20250728 Mon.html">しらさぎ編成その1</option>
        <option value="19971001現在編成-スーパー雷鳥1002A" data-parent="スーパー雷鳥(退役)" data-url="座席表/JR西日本/19971001現在 スーパー雷鳥1002A 20250728 Mon.html">しらさぎ編成その2パターンA</option>
        <option value="19971001現在編成-雷鳥1001A" data-parent="雷鳥(退役)" data-url="座席表/JR西日本/19971001現在 雷鳥1001A 20250728 Mon.html">しらさぎ編成その1</option>
        <option value="19971001現在編成-雷鳥1002A" data-parent="雷鳥(退役)" data-url="座席表/JR西日本/19971001現在 雷鳥1001B 20250728 Mon.html">しらさぎ編成その2パターンA</option>
    </select>
    <div id="contentDisplay" style="margin-top: 20px;">
        <p>ここに選択されたコンテンツが表示されます。</p>
        <button id="resetSelection">選択を初期化</button>
        <iframe id="dynamicIframe" src=""></iframe>
    </div>
<style>
select {
    margin: 5px;
    padding: 8px;
    border: 1px solid #ccc;
    border-radius: 4px;
    font-size: 1rem;
    width: 200px;
}

body {
    margin: 0;
    padding: 0;
    /* overflow: hidden; */
}

iframe {
    width: 100vw;
    height: 100vh;
    border: none;
    overflow: hidden;
}

iframe {
    border: none;
    display: block;
    margin: 0 auto;
    overflow: hidden;
}
</style>
<script>
$(document).ready(function() {

    /**
     * 次の階層以降のプルダウンをリセットし、無効化、オプションを非表示にする
     * @param {number} startLevel - リセットを開始する階層の番号
     */
    function resetNextLevels(startLevel) {
        for (let i = startLevel; i <= 5; i++) { // 階層の最大値を5に合わせる
            const $currentSelect = $(`#level${i}`);
            $currentSelect.val(''); // 選択をクリア

            // level1 以外は無効化、またはstartLevelが2以上の場合は無効化
            if (i > 1 || startLevel > 1) { // level1は常に有効にする
                $currentSelect.prop('disabled', true);
            } else {
                $currentSelect.prop('disabled', false); // level1は有効のまま
            }

            // level1 以外のオプションを非表示にする(選択してください、以外)
            // i === 1 (level1) の場合は、オプションを非表示にしないようにする
            if (i > 1) {
                $currentSelect.find('option:not([value=""])').hide();
            }
        }
    }

    /**
     * 指定されたプルダウンの関連オプションを表示し、有効化する
     * @param {string} selector - プルダウンのCSSセレクタ (例: '#level2')
     * @param {string} parentValue - 親のプルダウンで選択された値
     */
    function showRelatedOptions(selector, parentValue) {
        const $select = $(selector);
        $select.prop('disabled', false); // プルダウンを有効化

        // 親の値に紐づくオプションを表示
        $select.find(`option[data-parent="${parentValue}"]`).show();
        // 「選択してください」オプションも表示しておく
        $select.find('option[value=""]').show();
    }

    // 初期状態: level2 から level5 までのオプションを全て非表示にし、プルダウンを無効化
    resetNextLevels(2); // level2以降をリセットし無効化

    // 初期ロード時にlevel1を明示的に有効にする(念のため)
    $('#level1').prop('disabled', false);
    // level1の全オプションを表示する(初期状態では非表示になっていないはずだが、念のため)
    $('#level1').find('option').show();


    // --- イベントリスナーの設定 ---

    $('#level1').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(2); // level2以降をリセット
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level2', selectedParent);
        }
    });

    $('#level2').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(3);
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level3', selectedParent);
        }
    });

    $('#level3').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(4);
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level4', selectedParent);
        }
    });

    $('#level4').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(5);
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level5', selectedParent);
        }
    });

    // level5 の変更イベント (iframe表示に変更)
    $('#level5').on('change', function() {
        const selectedOption = $(this).find('option:selected');
        const finalSelectionValue = selectedOption.val();
        const targetUrl = selectedOption.data('url');

        const $dynamicIframe = $('#dynamicIframe');
        const $contentDisplayMessage = $('#contentDisplay p');

        if (targetUrl) {
            $contentDisplayMessage.hide();
            $dynamicIframe.attr('src', targetUrl).show();
            console.log("選択されたURLをiframeに表示:", targetUrl);

            // iframeのロード完了時に高さを調整
            $dynamicIframe.off('load').on('load', function() {
                try {
                    // 同じオリジンのコンテンツのみアクセス可能
                    const iframeContentHeight = this.contentWindow.document.body.scrollHeight;
                    $(this).css('height', iframeContentHeight + 'px');
                    console.log("iframeの高さを調整:", iframeContentHeight + "px");
                } catch (e) {
                    console.warn("iframeのコンテンツにアクセスできません。異なるオリジンである可能性があります。", e);
                    // 異なるオリジンの場合は、固定の高さに戻すか、スクロールを許可するなどの対応
                    $(this).css('height', '100vh'); // あるいは、適切なデフォルト値
                }
            });

        } else {
            $dynamicIframe.attr('src', '').hide();
            $dynamicIframe.css('height', '100vh'); // iframeをクリアしたら元の高さに戻すか、適切なデフォルト値
            $contentDisplayMessage.show();
            console.log("iframe表示クリア");
        }
    });

    // 「選択を初期化」ボタンのクリックイベントリスナー
    $('#resetSelection').on('click', function() {
        resetNextLevels(1); // 全てのレベルをリセット(level1も含む)
        $('#level1').prop('disabled', false); // level1を明示的に有効にする
        $('#level1').find('option').show(); // level1の全オプションを表示
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示
    });
});
</script>
</body>
</html>

スクリーンショット 2025-07-29 133809.png

例)

def greet
  puts Hello World
end

自分で試したこと

ここに問題・エラーに対して試したことを記載してください。
htmlで先に説明した2案を試したり、
geminiなどの生成aiを使用してみたりしましたが、有効な回答は得られず、
泣き寝入りの状態です。
どうしたらいいでしょうか?

1 likes

2Answer

iframe内のコンテンツにスクリプトを追加することは可能でしょうか。
iframe内コンテンツ(例えば19971001現在 スーパー雷鳥1001A 20250728 Mon.html)にて自身の高さをwindow.parent.postMessageで送信、親ページではそれを受け取り、iframeの高さを調整といった方法はどうでしょうか。
iframeやHTMLファイル直リンクの運用について詳しくないので間違いがあればすみません。

iframe内コンテンツに以下のコードを追加

<script>
  function sendHeightToParent() {
    const height = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
    console.log("iframeの高さを通知 : " + height);
    window.parent.postMessage({ height: height }, '*');
  }

  // 動的な変更を考慮して1秒ごとに高さを親ページに通知
  setInterval(sendHeightToParent, 1000);

  // 初回読み込み時にも通知
  window.addEventListener('DOMContentLoaded', sendHeightToParent);
</script>

親ページのスクリプトに以下のコードを追加

window.addEventListener('message', function(event) {
  console.log("iframe内コンテンツからメッセージを受信");
  if (event.data.height) {
    const height = event.data.height;
    console.log("iframe内コンテンツから取得した高さ : " + height);
    document.getElementById('dynamicIframe').style.height = height + 'px';
  }
});

親ページのlevel5変更時のiframe高さ調整のコードを削除

//            $dynamicIframe.off('load').on('load', function() {
//                try {
//                    // 同じオリジンのコンテンツのみアクセス可能
//                    const iframeContentHeight = this.contentWindow.document.body.scrollHeight;
//                    $(this).css('height', iframeContentHeight + 'px');
//                    console.log("iframeの高さを調整:", iframeContentHeight + "px");
//                } catch (e) {
//                    console.warn("iframeのコンテンツにアクセスできません。異なるオリジンである可能性があります。", e);
//                    // 異なるオリジンの場合は、固定の高さに戻すか、スクロールを許可するなどの対応
//                    $(this).css('height', '100vh'); // あるいは、適切なデフォルト値
//                }
//            });
0Like

ありがとうございます。失礼ですが、親ファイルのほうは少し、動作エラーになってしまったので、geminiのほうで修正させていただきました。

<script>
$(document).ready(function() {

    /**
     * 次の階層以降のプルダウンをリセットし、無効化、オプションを非表示にする
     * @param {number} startLevel - リセットを開始する階層の番号
     */
    function resetNextLevels(startLevel) {
        for (let i = startLevel; i <= 5; i++) { // 階層の最大値を5に合わせる
            const $currentSelect = $(`#level${i}`);
            $currentSelect.val(''); // 選択をクリア

            // level1 以外は無効化、またはstartLevelが2以上の場合は無効化
            if (i > 1 || startLevel > 1) { // level1は常に有効にする
                $currentSelect.prop('disabled', true);
            } else {
                $currentSelect.prop('disabled', false); // level1は有効のまま
            }

            // level1 以外のオプションを非表示にする(選択してください、以外)
            // i === 1 (level1) の場合は、オプションを非表示にしないようにする
            if (i > 1) {
                $currentSelect.find('option:not([value=""])').hide();
            }
        }
    }

    /**
     * 指定されたプルダウンの関連オプションを表示し、有効化する
     * @param {string} selector - プルダウンのCSSセレクタ (例: '#level2')
     * @param {string} parentValue - 親のプルダウンで選択された値
     */
    function showRelatedOptions(selector, parentValue) {
        const $select = $(selector);
        $select.prop('disabled', false); // プルダウンを有効化

        // 親の値に紐づくオプションを表示
        $select.find(`option[data-parent="${parentValue}"]`).show();
        // 「選択してください」オプションも表示しておく
        $select.find('option[value=""]').show();
    }

    // 初期状態: level2 から level5 までのオプションを全て非表示にし、プルダウンを無効化
    resetNextLevels(2); // level2以降をリセットし無効化

    // 初期ロード時にlevel1を明示的に有効にする(念のため)
    $('#level1').prop('disabled', false);
    // level1の全オプションを表示する(初期状態では非表示になっていないはずだが、念のため)
    $('#level1').find('option').show();


    // --- イベントリスナーの設定 ---

    $('#level1').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(2); // level2以降をリセット
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level2', selectedParent);
        }
    });

    $('#level2').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(3);
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level3', selectedParent);
        }
    });

    $('#level3').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(4);
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level4', selectedParent);
        }
    });

    $('#level4').on('change', function() {
        const selectedParent = $(this).val();
        resetNextLevels(5);
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示

        if (selectedParent) {
            showRelatedOptions('#level5', selectedParent);
        }
    });

    // level5 の変更イベント (iframe表示に変更)
    $('#level5').on('change', function() {
        const selectedOption = $(this).find('option:selected');
        const finalSelectionValue = selectedOption.val();
        const targetUrl = selectedOption.data('url');

        const $dynamicIframe = $('#dynamicIframe');
        const $contentDisplayMessage = $('#contentDisplay p');

        if (targetUrl) {
            $contentDisplayMessage.hide();
            $dynamicIframe.attr('src', targetUrl).show();
            console.log("選択されたURLをiframeに表示:", targetUrl);

            // iframeのロード完了時に高さを調整
window.addEventListener('message', function(event) {
  console.log("iframe内コンテンツからメッセージを受信");
  if (event.data.height) {
    const height = event.data.height;
    console.log("iframe内コンテンツから取得した高さ : " + height);
    document.getElementById('dynamicIframe').style.height = height + 'px';
  }
});

        } else {
            $dynamicIframe.attr('src', '').hide();
            $dynamicIframe.css('height', '100vh'); // iframeをクリアしたら元の高さに戻すか、適切なデフォルト値
            $contentDisplayMessage.show();
            console.log("iframe表示クリア");
        }
    });

    // 「選択を初期化」ボタンのクリックイベントリスナー
    $('#resetSelection').on('click', function() {
        resetNextLevels(1); // 全てのレベルをリセット(level1も含む)
        $('#level1').prop('disabled', false); // level1を明示的に有効にする
        $('#level1').find('option').show(); // level1の全オプションを表示
        $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
        $('#contentDisplay p').show(); // 初期メッセージを表示
    });
});
</script>

子ファイルは先ほどのもので問題なく作動しました。
大変貴重なご意見を承り誠にありがとうございます。

0Like

Comments

  1. イベントリスナーの登録window.addEventListener('message', function(event) {...は一度だけ実行してあげればいいので、$(document).ready(function() {の直下に記述するほうがベターかと思います。
    // 「選択を初期化」ボタンのクリックイベントリスナーと同じようなタイミングです。

    具体的には以下のようになります。

    <script>
    $(document).ready(function() {
    
    ... 省略 ...
    
        // 「選択を初期化」ボタンのクリックイベントリスナー
        $('#resetSelection').on('click', function() {
            resetNextLevels(1); // 全てのレベルをリセット(level1も含む)
            $('#level1').prop('disabled', false); // level1を明示的に有効にする
            $('#level1').find('option').show(); // level1の全オプションを表示
            $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
            $('#contentDisplay p').show(); // 初期メッセージを表示
        });
    
        // メッセージ受信時のイベントリスナー
        window.addEventListener('message', function(event) {
            console.log("iframe内コンテンツからメッセージを受信");
            if (event.data.height) {
                const height = event.data.height;
                console.log("iframe内コンテンツから取得した高さ : " + height);
                document.getElementById('dynamicIframe').style.height = height + 'px';
            }
        });
    
    });
    </script>
    
  2. @sembokulove

    Questioner

    すみません、
    恐れ入りますが、window.addEventListener('message', function(event) {...の設置位置が少々わかりにくいです。
    先ほどの

        // 「選択を初期化」ボタンのクリックイベントリスナー
        $('#resetSelection').on('click', function() {
            resetNextLevels(1); // 全てのレベルをリセット(level1も含む)
            $('#level1').prop('disabled', false); // level1を明示的に有効にする
            $('#level1').find('option').show(); // level1の全オプションを表示
            $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
            $('#contentDisplay p').show(); // 初期メッセージを表示
        });
    
        // メッセージ受信時のイベントリスナー
        window.addEventListener('message', function(event) {
            console.log("iframe内コンテンツからメッセージを受信");
            if (event.data.height) {
                const height = event.data.height;
                console.log("iframe内コンテンツから取得した高さ : " + height);
                document.getElementById('dynamicIframe').style.height = height + 'px';
            }
        });
    
    });
    </script>
    ```は最後に設置するのはわかりますが、
    他のjsの全コードを大変お手数ですが、ご掲示願えれば幸いです。
    
    
  3. level5のchangeイベントの度に今回追加したイベントリスナー登録処理が実行されてしまうため、例えば以下のような操作を行うとwindow.addEventListener('message', function(event) { ...の処理が重複して呼び出されてしまいます。
    ・level5 にて「しらさぎ編成その1」を選択
    ・level5 にて「しらさぎ編成その2パターンA」を選択
    ・level5 にて「しらさぎ編成その1」を選択
    恐らくメッセージの受信の度にconsole.log("iframe内コンテンツからメッセージを受信");のログが3回コンソールに表示されることが確認できると思います。

    親ページのイベントリスナー登録はページ読み込み完了時に1度だけ実行すればいいので、以下のようになると思います。
    // ★ページの読み込み完了時に一度だけイベントリスナーを登録するの処理は、さかのぼれば$(document).ready(function() {の直下で呼び出されているので1度だけ実行されます。
    iframe内コンテンツのスクリプトに変更点はありません。

    親ページのスクリプト

    <script>
    $(document).ready(function() {
    
        /**
         * 次の階層以降のプルダウンをリセットし、無効化、オプションを非表示にする
         * @param {number} startLevel - リセットを開始する階層の番号
         */
        function resetNextLevels(startLevel) {
            for (let i = startLevel; i <= 5; i++) { // 階層の最大値を5に合わせる
                const $currentSelect = $(`#level${i}`);
                $currentSelect.val(''); // 選択をクリア
    
                // level1 以外は無効化、またはstartLevelが2以上の場合は無効化
                if (i > 1 || startLevel > 1) { // level1は常に有効にする
                    $currentSelect.prop('disabled', true);
                } else {
                    $currentSelect.prop('disabled', false); // level1は有効のまま
                }
    
                // level1 以外のオプションを非表示にする(選択してください、以外)
                // i === 1 (level1) の場合は、オプションを非表示にしないようにする
                if (i > 1) {
                    $currentSelect.find('option:not([value=""])').hide();
                }
            }
        }
    
        /**
         * 指定されたプルダウンの関連オプションを表示し、有効化する
         * @param {string} selector - プルダウンのCSSセレクタ (例: '#level2')
         * @param {string} parentValue - 親のプルダウンで選択された値
         */
        function showRelatedOptions(selector, parentValue) {
            const $select = $(selector);
            $select.prop('disabled', false); // プルダウンを有効化
    
            // 親の値に紐づくオプションを表示
            $select.find(`option[data-parent="${parentValue}"]`).show();
            // 「選択してください」オプションも表示しておく
            $select.find('option[value=""]').show();
        }
    
        // 初期状態: level2 から level5 までのオプションを全て非表示にし、プルダウンを無効化
        resetNextLevels(2); // level2以降をリセットし無効化
    
        // 初期ロード時にlevel1を明示的に有効にする(念のため)
        $('#level1').prop('disabled', false);
        // level1の全オプションを表示する(初期状態では非表示になっていないはずだが、念のため)
        $('#level1').find('option').show();
    
    
        // --- イベントリスナーの設定 ---
    
        $('#level1').on('change', function() {
            const selectedParent = $(this).val();
            resetNextLevels(2); // level2以降をリセット
            $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
            $('#contentDisplay p').show(); // 初期メッセージを表示
    
            if (selectedParent) {
                showRelatedOptions('#level2', selectedParent);
            }
        });
    
        $('#level2').on('change', function() {
            const selectedParent = $(this).val();
            resetNextLevels(3);
            $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
            $('#contentDisplay p').show(); // 初期メッセージを表示
    
            if (selectedParent) {
                showRelatedOptions('#level3', selectedParent);
            }
        });
    
        $('#level3').on('change', function() {
            const selectedParent = $(this).val();
            resetNextLevels(4);
            $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
            $('#contentDisplay p').show(); // 初期メッセージを表示
    
            if (selectedParent) {
                showRelatedOptions('#level4', selectedParent);
            }
        });
    
        $('#level4').on('change', function() {
            const selectedParent = $(this).val();
            resetNextLevels(5);
            $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
            $('#contentDisplay p').show(); // 初期メッセージを表示
    
            if (selectedParent) {
                showRelatedOptions('#level5', selectedParent);
            }
        });
    
        // level5 の変更イベント (iframe表示に変更)
        $('#level5').on('change', function() {
            const selectedOption = $(this).find('option:selected');
            const finalSelectionValue = selectedOption.val();
            const targetUrl = selectedOption.data('url');
    
            const $dynamicIframe = $('#dynamicIframe');
            const $contentDisplayMessage = $('#contentDisplay p');
    
            if (targetUrl) {
                $contentDisplayMessage.hide();
                $dynamicIframe.attr('src', targetUrl).show();
                console.log("選択されたURLをiframeに表示:", targetUrl);
    
                // iframeのロード完了時に高さを調整
                // ★level5 の変更の度にイベントリスナーが登録されてしまうのでコメントアウト
    //window.addEventListener('message', function(event) {
    //  console.log("iframe内コンテンツからメッセージを受信");
    //  if (event.data.height) {
    //    const height = event.data.height;
    //    console.log("iframe内コンテンツから取得した高さ : " + height);
    //    document.getElementById('dynamicIframe').style.height = height + 'px';
    //  }
    //});
    
            } else {
                $dynamicIframe.attr('src', '').hide();
                $dynamicIframe.css('height', '100vh'); // iframeをクリアしたら元の高さに戻すか、適切なデフォルト値
                $contentDisplayMessage.show();
                console.log("iframe表示クリア");
            }
        });
    
        // 「選択を初期化」ボタンのクリックイベントリスナー
        $('#resetSelection').on('click', function() {
            resetNextLevels(1); // 全てのレベルをリセット(level1も含む)
            $('#level1').prop('disabled', false); // level1を明示的に有効にする
            $('#level1').find('option').show(); // level1の全オプションを表示
            $('#dynamicIframe').attr('src', '').hide(); // iframeをクリア
            $('#contentDisplay p').show(); // 初期メッセージを表示
        });
        
        // メッセージ受信時のイベントリスナー
        // ★ページの読み込み完了時に一度だけイベントリスナーを登録する
        window.addEventListener('message', function(event) {
            console.log("iframe内コンテンツからメッセージを受信");
            if (event.data.height) {
                const height = event.data.height;
                console.log("iframe内コンテンツから取得した高さ : " + height);
                document.getElementById('dynamicIframe').style.height = height + 'px';
            }
        });
    });
    </script>
    
  4. @sembokulove

    Questioner

    お忙しい中貴重なお時間をお割き頂き、たいへんありがとうございます。
    jsがきちんと正常に動きました。
    これをもって終了とさせていただきます。

Your answer might help someone💌