「Widget:Custom map」の版間の差分

提供:メタファー リファンタジオ 攻略Wiki
移動先:案内検索
編集の要約なし
編集の要約なし
 
(同じ利用者による、間の51版が非表示)
1行目: 1行目:
<includeonly>
<includeonly>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<!-- Required CSS -->
 
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<script src="https://dq.h1g.jp/leaflet/leaflet.js" ></script>
<script src="https://dq.h1g.jp/img/dq10_offline/map/js/leaflet-easy-button.js"></script>
<script src="https://dq.h1g.jp/img/dq10_offline/map/js/leaflet-tag-filter-button.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
<script src="https://dq.h1g.jp/leaflet/custom-leaflet-draw-locale.js" ></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.7.2/lightgallery.min.js"></script>
 
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/> 
<link rel="stylesheet" href="https://dq.h1g.jp/img/dq10_offline/map/css/leaflet-easy-button.css" />
<link rel="stylesheet" href="https://dq.h1g.jp/img/dq10_offline/map/css/leaflet-easy-button.css" />
<link rel="stylesheet" href="https://dq.h1g.jp/img/dq10_offline/map/css/leaflet-tag-filter-button.css" />
<link rel="stylesheet" href="https://dq.h1g.jp/img/dq10_offline/map/css/leaflet-tag-filter-button.css" />
17行目: 9行目:




<script type="text/javascript">
<!-- Required JS Libraries -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://dq.h1g.jp/leaflet/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw-src.js"></script>
<script src="https://dq.h1g.jp/leaflet/custom-leaflet-draw-locale.js"></script>
<script src="https://dq.h1g.jp/img/dq10_offline/map/js/leaflet-easy-button.js"></script>
<script src="https://dq.h1g.jp/img/dq10_offline/map/js/leaflet-tag-filter-button.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.7.2/lightgallery.min.js"></script>


let map;
<!-- Global Configuration -->
var drawnItems;
<script>
var drawControl;
// Initialize WidgetMap namespace with explicit function placeholder
var editMode = false;
window.WidgetMap = {
// APIベースURLを定数として定義
     map: null,
const API_BASE_URL = 'https://prd-h1g-elb-2067013247.ap-northeast-1.elb.amazonaws.com/metaphor_refantazio';
    drawnItems: null,
 
     drawControl: null,
///////////////
     editMode: false,
// Wikiのクロスサイト影響をデバッグするためのツール
     api: {},
window.debugWikiURLSwitching = function() {
     popups: {},
     console.group('=== Wiki URL Switching Debug ===');
     icons: {},
   
     // 明示的な関数プレースホルダー
    // 現在のWikiコンテキストを保存
     initializeMap: function() {
    const currentWikiContext = {
         console.error('Map initialization not yet loaded');
        baseURL: API_BASE_URL,
         return null;
        path: window.location.pathname,
        timestamp: new Date().toISOString()
     };
   
    // ローカルストレージのWiki関連データを確認
    console.log('LocalStorage Wiki Data:');
     Object.keys(localStorage).forEach(key => {
        if (key.includes('wiki') || key.includes('map') ||
            key.includes('rs2r') || key.includes('mario') ||
            key.includes('zelda') || key.includes('leaflet')) {
            console.log(`${key}:`, localStorage.getItem(key));
        }
     });
 
    // セッションストレージも確認
    console.log('\nSessionStorage Wiki Data:');
    Object.keys(sessionStorage).forEach(key => {
        if (key.includes('wiki') || key.includes('map') ||
            key.includes('rs2r') || key.includes('mario') ||
            key.includes('zelda') || key.includes('leaflet')) {
            console.log(`${key}:`, sessionStorage.getItem(key));
        }
    });
 
    // グローバル変数のチェック
     console.log('\nGlobal Variables Check:');
    const relevantGlobals = ['API_BASE_URL', 'map', 'drawnItems', 'L'];
    relevantGlobals.forEach(varName => {
        if (window[varName]) {
            console.log(`${varName} exists:`, {
                type: typeof window[varName],
                value: varName === 'API_BASE_URL' ? window[varName] : '[Object]'
            });
        }
     });
 
    // Cookieもチェック
    console.log('\nRelevant Cookies:');
    document.cookie.split(';').forEach(cookie => {
        if (cookie.includes('wiki') || cookie.includes('map') ||
            cookie.includes('rs2r') || cookie.includes('mario') ||
            cookie.includes('zelda')) {
            console.log('Cookie:', cookie.trim());
        }
    });
 
    // APIリクエストの監視を強化
    const originalAjax = $.ajax;
    $.ajax = function(settings) {
        // URLの変更を検出
        const originalUrl = settings.url;
        const knownWikis = [
            'rs2r',
            'mario_luigi_brothership',
            'zelda_eow',
            'metaphor_refantazio'
        ];
       
        // 意図しないWikiへのURLスイッチを検出
        const detectedWiki = knownWikis.find(wiki =>
            settings.url.includes(wiki) && !API_BASE_URL.includes(wiki)
        );
       
        if (detectedWiki) {
            console.warn('URL Switch Detected!', {
                intendedWiki: API_BASE_URL.split('/').pop(),
                detectedWiki: detectedWiki,
                originalUrl: originalUrl,
                stack: new Error().stack
            });
        }
 
        return originalAjax.apply(this, arguments);
    };
 
     // Leafletマップのクリーンアップ状態を確認
     console.log('\nLeaflet State Check:');
    if (window.map) {
         console.log('Map instance exists');
         console.log('Drawn items count:', drawnItems?.getLayers().length || 0);
       
        // マップのイベントリスナーを確認
        const mapEvents = map._events;
        console.log('Map event listeners:', Object.keys(mapEvents));
     }
     }
    // 前回のマップ情報が残っていないか確認
    if (window.previousMapState) {
        console.warn('Previous map state detected:', window.previousMapState);
    }
    // クリーンアップ関数の提供
    window.cleanupMapState = function() {
        console.group('Cleaning up map state');
       
        // マップインスタンスのクリーンアップ
        if (window.map) {
            map.remove();
            window.map = null;
        }
       
        // drawnItemsのクリーンアップ
        if (window.drawnItems) {
            drawnItems.clearLayers();
            window.drawnItems = null;
        }
       
        // Leaflet関連のグローバル変数をクリーンアップ
        ['editControl', 'drawControl', 'iconDefinitions'].forEach(varName => {
            if (window[varName]) {
                window[varName] = null;
            }
        });
       
        // ローカルストレージの特定のアイテムをクリア
        Object.keys(localStorage).forEach(key => {
            if (key.includes('map') || key.includes('leaflet')) {
                localStorage.removeItem(key);
            }
        });
       
        console.log('Map state cleaned up');
        console.groupEnd();
    };
    console.log('\nDebug tools installed. Use cleanupMapState() to reset map state.');
    console.groupEnd();
};
};


// URLの履歴を追跡
// プラグインの読み込み確認機能
window.trackURLHistory = function() {
function checkPlugins() {
     const urlHistory = sessionStorage.getItem('urlHistory') ?
     console.log('Checking Leaflet plugins...');
        JSON.parse(sessionStorage.getItem('urlHistory')) : [];
      
      
     urlHistory.push({
     // Leaflet本体
        timestamp: new Date().toISOString(),
    console.log('Leaflet version:', L.version);
        url: window.location.href,
        apiBaseUrl: API_BASE_URL
    });
      
      
     // 最新の10件のみ保持
     // Leaflet.Draw
     if (urlHistory.length > 10) {
     if (L.Draw) {
         urlHistory.shift();
         console.log('Leaflet.Draw loaded:', {
            Draw: !!L.Draw,
            DrawToolbar: !!L.DrawToolbar,
            Polyline: !!L.Draw.Polyline
        });
    } else {
        console.error('Leaflet.Draw not loaded properly');
     }
     }
   
}
    sessionStorage.setItem('urlHistory', JSON.stringify(urlHistory));
   
    console.group('URL History');
    urlHistory.forEach((entry, index) => {
        console.log(`${index + 1}:`, entry);
    });
    console.groupEnd();
};
//////////////////////////////////////////////
 
window.savePopupContent = savePopupContent;
 
// 表示する画像
var imageBase = {
  url: '<!--{$img}-->',
  width: <!--{$imgwidth}-->,          // 画像のサイズ
  height: <!--{$imgheight}-->
};
 
// 地図初期化
var imageBounds = L.latLngBounds(
  [0, 0],
  [imageBase.height, imageBase.width],
 
);
 
map = L.map('map', {
  crs: L.CRS.Simple,
  maxBounds: imageBounds.pad(0.5),
  minZoom: <!--{$minzoom}-->, // minZoomを0に設定
  maxZoom: <!--{$maxzoom}-->,


});
map.fitBounds(imageBounds);
L.imageOverlay(imageBase.url, imageBounds,{
  attribution: '<a href="https://h1g.jp/" target="_blank">【ヘイグ】</a>'
}).addTo(map);


var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);




// Leaflet.Draw
// Initialize API base URL
var drawnItems = new L.FeatureGroup();
(function() {
map.addLayer(drawnItems);
    const currentUrl = new URL(window.location.href);
    const baseUrl = currentUrl.origin + currentUrl.pathname.split('/').slice(0, -1).join('/');
    window.API_BASE_URL = baseUrl;
    console.log('API_BASE_URL initialized:', baseUrl);
})();


drawControl = new L.Control.Draw({
// Map configuration
    edit: {
window.mapConfig = {
         featureGroup: drawnItems,
    imageUrl: '<!--{$img}-->',
         poly: {
    imageWidth: <!--{$imgwidth}-->,
            allowIntersection: false
    imageHeight: <!--{$imgheight}-->,
         }
    minZoom: <!--{$minzoom}-->,
    maxZoom: <!--{$maxzoom}-->,
    geoJsonPage: '<!--{$geojson}-->',
    iconUrls: {
        icon1: '<!--{$icon1|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-blue.png"}-->',
        icon2: '<!--{$icon2|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-red.png"}-->',
        icon3: '<!--{$icon3|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-violet.png"}-->',
        icon4: '<!--{$icon4|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-green.png"}-->',
        icon5: '<!--{$icon5|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-gold.png"}-->',
         icon6: '<!--{$icon6|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-black.png"}-->',
         icon7: '<!--{$icon7|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-orange.png"}-->',
        icon8: '<!--{$icon8|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-yellow.png"}-->',
         icon9: '<!--{$icon9|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-grey.png"}-->',
        icon10: '<!--{$icon10|default:"https://dq.h1g.jp/img/marker-icon-img/marker-icon-brown.png"}-->'
     },
     },
     draw: {
     filters: {
         polygon: false,
         filter1: '<!--{$filter1|default:"分類1"}-->',
         polyline: false,
        filter2: '<!--{$filter2|default:"分類2"}-->',
         rectangle: false,
        filter3: '<!--{$filter3|default:"分類3"}-->',
         circle: true,
        filter4: '<!--{$filter4|default:"分類4"}-->',
         marker: true,
         filter5: '<!--{$filter5|default:"分類5"}-->',
         circlemarker: false
        filter6: '<!--{$filter6|default:"分類6"}-->',
         filter7: '<!--{$filter7|default:"分類7"}-->',
         filter8: '<!--{$filter8|default:"分類8"}-->',
         filter9: '<!--{$filter9|default:"分類9"}-->',
         filter10: '<!--{$filter10|default:"分類10"}-->'
     }
     }
});
map.addControl(drawControl);
// 初期状態では編集モードを無効にする
drawControl.remove();
map.on(L.Draw.Event.CREATED, function (event) {
    var layer = event.layer;
    if (layer instanceof L.Marker) {
        layer.setIcon(iconDefinitions.icon1);
        layer.options.popupData = {title: '', content: '', iconType: 'icon1'};
        var popupContent =
            '<div>' +
            '<textarea id="popup-title" cols="30" rows="1" placeholder="タイトル"></textarea>' +
            '<textarea id="popup-content" cols="30" rows="2" placeholder="内容"></textarea>' +
            '<select id="icon-type">' +
            '<option value="icon1" selected>アイコン1</option>' +
            '<option value="icon2">アイコン2</option>' +
            '<option value="icon3">アイコン3</option>' +
            '<option value="icon4">アイコン4</option>' +
            '<option value="icon5">アイコン5</option>' +
            '<option value="icon6">アイコン6</option>' +
            '</select>' +
            '<button onclick="savePopupContent(this)">保存</button>' +
            '</div>';
        layer.bindPopup(popupContent);
    } else {
        layer.bindPopup('No description');
    }
    createEditablePopup(layer);
    drawnItems.addLayer(layer);
    if (layer instanceof L.Marker) {
        layer.openPopup();
    }
});
//////////////////権限を確認
function checkUserGroup(group, callback) {
    $.ajax({
        url: API_BASE_URL + '/api.php',
        data: {
            action: 'query',
            meta: 'userinfo',
            uiprop: 'groups',
            format: 'json'
        },
        type: 'GET',
        success: function(data) {
            var userGroups = data.query.userinfo.groups;
            var isInGroup = userGroups.indexOf(group) !== -1;
            callback(isInGroup);
        },
        error: function() {
            console.error('Failed to check user group');
            callback(false);
        }
    });
}
//////////////////////////////////////////////////////////////
// アイコンの定義
var iconDefinitions = {
    icon1: L.icon({
      iconUrl: '<!--{$icon1|default:'https://dq.h1g.jp/img/marker-icon-img/marker-icon-blue.png'}-->',
      shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
      iconSize: [25, 41],
      iconAnchor: [12, 41],
      popupAnchor: [1, -41],
      shadowSize: [41, 41]
    }),
    icon2: L.icon({
      iconUrl: '<!--{$icon2|default:'https://dq.h1g.jp/img/marker-icon-img/marker-icon-red.png'}-->',
      shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
      iconSize: [25, 41],
      iconAnchor: [12, 41],
      popupAnchor: [1, -41],
      shadowSize: [41, 41]
    }),
    icon3: L.icon({
      iconUrl: '<!--{$icon3|default:'https://dq.h1g.jp/img/marker-icon-img/marker-icon-violet.png'}-->',
      shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
      iconSize: [25, 41],
      iconAnchor: [12, 41],
      popupAnchor: [1, -41],
      shadowSize: [41, 41]
    }),
    icon4: L.icon({
      iconUrl: '<!--{$icon4|default:'https://dq.h1g.jp/img/marker-icon-img/marker-icon-green.png'}-->',
      shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
      iconSize: [25, 41],
      iconAnchor: [12, 41],
      popupAnchor: [1, -41],
      shadowSize: [41, 41]
    }),
    icon5: L.icon({
      iconUrl: '<!--{$icon5|default:'https://dq.h1g.jp/img/marker-icon-img/marker-icon-gold.png'}-->',
      shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
      iconSize: [25, 41],
      iconAnchor: [12, 41],
      popupAnchor: [1, -41],
      shadowSize: [41, 41]
    }),
    icon6: L.icon({
      iconUrl: '<!--{$icon6|default:'https://dq.h1g.jp/img/marker-icon-img/marker-icon-black.png'}-->',
      shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
      iconSize: [25, 41],
      iconAnchor: [12, 41],
      popupAnchor: [1, -41],
      shadowSize: [41, 41]
    })
};
};
</script>


 
<!-- Load scripts sequentially -->
// ポップアップの作成
<script>
function createEditablePopup(layer) {
// Clear any existing WidgetMap object
    var popupData = layer.options.popupData || {};
if (window.WidgetMap) {
    var title = popupData.title || '';
     console.log('[Init] Clearing existing WidgetMap object');
    var content = popupData.content || '';
     delete window.WidgetMap;
    var iconType = popupData.iconType || 'icon1';
 
    layer.on('popupopen', function() {
        var popup = this.getPopup();
        var popupData = this.options.popupData || {};
        var title = popupData.title || '';
        var content = popupData.content || '';
        var iconType = popupData.iconType || 'icon1';
 
 
 
        // タイトルと内容が両方空の場合、ポップアップを表示しない
        if (!editMode && title === '' && content === '') {
            layer.closePopup();
            // カーソルをデフォルトに設定
            layer._icon.style.cursor = 'default';
            return;
        }
 
        if (editMode) {  // 編集モードの場合のみtextareaを表示
            var iconSelector = '';
            if (layer instanceof L.Marker) {
                iconSelector = '<select id="icon-type">' +
                    '<option value="icon1"' + (iconType === 'icon1' ? ' selected' : '') + '>アイコン1</option>' +
                    '<option value="icon2"' + (iconType === 'icon2' ? ' selected' : '') + '>アイコン2</option>' +
                    '<option value="icon3"' + (iconType === 'icon3' ? ' selected' : '') + '>アイコン3</option>' +
                    '<option value="icon4"' + (iconType === 'icon4' ? ' selected' : '') + '>アイコン4</option>' +
                    '<option value="icon5"' + (iconType === 'icon5' ? ' selected' : '') + '>アイコン5</option>' +
                    '<option value="icon6"' + (iconType === 'icon6' ? ' selected' : '') + '>アイコン6</option>' +
                '</select>';
            }
 
            var editableContent =
                '<div>' +
                '<textarea id="popup-title" cols="60" rows="3" placeholder="タイトル">' + title + '</textarea>' +
                '<textarea id="popup-content" cols="60" rows="10" placeholder="内容">' + content + '</textarea>' +
                iconSelector +
                '<button onclick="savePopupContent(this)">保存</button>' +
                '</div>';
            popup.setContent(editableContent);
        } else {
            // 編集モードでない場合は表示用のコンテンツを設定
            if (title === '' && content === '') {
                layer.unbindPopup(); // タイトルと内容が空の場合はポップアップを表示しない
            } else {
                var displayContent = '<strong>' + title + '</strong><br>' + content;
                var renderedContent = renderMediaWikiContent(displayContent);
                popup.setContent(renderedContent);
            }
        }
    });
 
     // 既にポップアップが設定されている場合に備え、再設定
    if (!(title === '' && content === '')) {
        var displayContent = '<strong>' + title + '</strong><br>' + content;
        var renderedContent = renderMediaWikiContent(displayContent);
        layer.bindPopup(renderedContent);
    }
}
 
 
 
 
// MediaWikiコンテンツのレンダリング
function renderMediaWikiContent(content) {
    var renderedContent = '';
    $.ajax({
        url: API_BASE_URL + '/api.php',
        data: {
            action: 'parse',
            text: content,
            format: 'json'
        },
        async: false,
        success: function(data) {
            renderedContent = data.parse.text['*'];
            // レンダリング後の画像処理
            setTimeout(function() {
                initLightGallery(renderedContent);
            }, 100);
        },
        error: function() {
            console.error('Failed to render MediaWiki content');
        }
    });
    return renderedContent;
}
 
 
// LightGalleryの初期化を修正
function initLightGallery(content) {
    const popupContent = $('.leaflet-popup-content');
   
    // 既存のLightGalleryインスタンスを破棄
    if (popupContent.data('lightGallery')) {
        popupContent.data('lightGallery').destroy(true);
    }
 
    // 既存のlg-containerを削除
    $('.lg-container').remove();
   
    popupContent.find('img').each(function() {
        const img = $(this);
        // gallery-itemクラスを持つdivで既に囲まれていない場合のみ処理
        if (!img.parent().hasClass('gallery-item')) {
            let fullSizeUrl = convertToFullSize(img.attr('src'));
            img.wrap('<div class="gallery-item" data-src="' + fullSizeUrl + '"></div>');
        }
    });
 
    // LightGalleryを初期化(ナビゲーション矢印を非表示に)
    if (!popupContent.data('lightGallery')) {
        lightGallery(popupContent[0], {
            selector: '.gallery-item',
            plugins: [],
            speed: 500,
            download: false,
            counter: false,
            enableDrag: false,
            enableTouch: false,
            hideControlOnEnd: true,
            controls: false,
            prevHtml: '',
            nextHtml: '',
            backdropDuration: 300,  // 背景のフェード時間
        });
    }
}
 
 
// ポップアップが閉じられたときの処理を追加
map.on('popupclose', function(e) {
    const popupContent = $(e.popup.getContent());
    if (popupContent.data('lightGallery')) {
        popupContent.data('lightGallery').destroy(true);
    }
});
 
// MediaWikiの画像URLを最大サイズに変換する関数
function convertToFullSize(url) {
    // MediaWikiのサムネイルURLをパースして最大サイズのURLに変換
    if (url.includes('/thumb/')) {
        // /thumb/を除去し、最後の/以降を削除して元のファイル名に戻す
        return url.replace('/thumb/', '/')
                .replace(/\/\d+px-[^/]+$/, '');
    }
    return url;
}
 
// ポップアップが開かれたときのイベントを追加
map.on('popupopen', function(e) {
    setTimeout(function() {
        initLightGallery(e.popup.getContent());
    }, 100);
});
 
 
// マップのクリーンアップ処理も追加
map.on('unload', function() {
    $('.lg-container').remove();
    $('.leaflet-popup-content').each(function() {
        if ($(this).data('lightGallery')) {
            $(this).data('lightGallery').destroy(true);
        }
    });
});
 
/// スタイルを更新
const styles = `
<style>
.gallery-item {
    cursor: pointer;
    display: inline-block;
}
.gallery-item img {
    max-width: 200px;
    height: auto;
    transition: transform 0.3s ease;
}
.gallery-item:hover img {
    transform: scale(1.05);
}
 
.lg-img-wrap {
    text-align: center;
}
.lg-img-wrap img {
    max-height: 90vh !important;
    max-width: 90vw !important;
    object-fit: contain;
}
/* ナビゲーション矢印を非表示 */
.lg-next, .lg-prev {
    display: none !important;
}
</style>
`;
 
 
 
// ポップアップの内容を保存
function savePopupContent(button) {
    var popup = button.closest('.leaflet-popup');
    var content = popup.querySelector('.leaflet-popup-content');
    var title = content.querySelector('#popup-title').value;
    var text = content.querySelector('#popup-content').value;
    var iconType = content.querySelector('#icon-type') ? content.querySelector('#icon-type').value : null;
   
    var layer = drawnItems.getLayers().find(function(layer) {
        return layer.getPopup() && layer.getPopup().getElement() === popup;
     });
   
    if (layer) {
        var savedContent = '<strong>' + title + '</strong><br>' + text;
        layer.setPopupContent(savedContent);
        layer.options.popupData = {title: title, content: text, iconType: iconType};
       
        // ポップアップを更新した後にLightGalleryを再初期化
        setTimeout(function() {
            initLightGallery(savedContent);
        }, 100);
       
        layer.closePopup();
        layer.openPopup();
    }
}
}


// Initialize fresh WidgetMap namespace
window.WidgetMap = {
    map: null,
    drawnItems: null,
    drawControl: null,
    editMode: false,
    api: {},
    popups: {},
    icons: {}
};


// 編集イベントのリスナーも追加
function loadScriptsSequentially() {
map.on(L.Draw.Event.EDITED, function (event) {
     function loadScript(src) {
     var layers = event.layers;
         return new Promise((resolve, reject) => {
    layers.eachLayer(function (layer) {
            console.log('[Script Loader] Loading:', src);
         drawnItems.addLayer(layer);
            const script = document.createElement('script');
    });
            script.src = src;
});
            script.onload = () => {
 
                console.log('[Script Loader] Successfully loaded:', src);
// 削除イベントのリスナーも追加
                if (src.includes('WidgetMap-core.js')) {
map.on(L.Draw.Event.DELETED, function (event) {
                    // コア読み込み後の検証を強化
    var layers = event.layers;
                    const verification = {
    layers.eachLayer(function (layer) {
                        hasWidgetMap: !!window.WidgetMap,
        drawnItems.removeLayer(layer);
                        initializeMapType: typeof window.WidgetMap.initializeMap,
    });
                        isFunction: typeof window.WidgetMap.initializeMap === 'function'
});
                    };
 
                    console.log('[Script Loader] Core verification:', verification);
// 編集ボタン
                      
var editButton = L.easyButton({
                     if (!verification.isFunction) {
    states: [{
                        console.error('[Script Loader] initializeMap not properly defined');
        stateName: 'enable-edit',
                        reject(new Error(`initializeMap not properly defined. Type: ${verification.initializeMapType}`));
        icon: '<img src="https://dq.h1g.jp/img/marker-icon-img/edit-solid.svg">',
                        return;
        title: 'マップを編集する',
                     }
        onClick: function(btn, map) {
//          checkUserGroup('map-edit-member', function(isInGroup) {
          checkUserGroup('sysop', function(isInGroup) {
//          checkUserGroup('internal-staff', function(isInGroup) {
            if (isInGroup) {
                     editMode = true;
                     map.addControl(drawControl);
                    btn.state('disable-edit');
                    updateAllPopups();
                    saveButton.addTo(map); // saveButtonを表示する
                } else {
//                    alert('あなたには編集権限がありません。\n攻略に参加することでマップが編集できるようになります。');
                     alert('あなたには編集権限がありません。');
                 }
                 }
            });
                resolve();
        }
             };
    }, {
             script.onerror = (error) => reject(new Error(`Failed to load ${src}: ${error}`));
        stateName: 'disable-edit',
             document.head.appendChild(script);
        icon: '<img src="https://dq.h1g.jp/img/marker-icon-img/edit-solid.svg">',
        title: '編集の終了',
        onClick: function(btn, map) {
            editMode = false;
             drawControl.remove();
            btn.state('enable-edit');
            updateAllPopups();
            saveButton.remove(); // saveButtonを非表示にする
        }
    }]
}).addTo(map);
 
function updateAllPopups() {
    drawnItems.eachLayer(function(layer) {
        if (layer.getPopup()) {
            layer.closePopup();
             if (editMode) {
                createEditablePopup(layer);
                layer.openPopup();
            } else if (!(layer.options.popupData && layer.options.popupData.title === '' && layer.options.popupData.content === '')) {
                layer.bindPopup(layer.options.popupData.title + "<br>" + layer.options.popupData.content);
            }
        }
    });
}
 
// 保存ボタン
var saveButton = L.easyButton('<img src="https://dq.h1g.jp/img/marker-icon-img/save-solid.svg">', function() {
    if (editMode) {
        var geoJSONData = convertToGeoJSON(drawnItems);
        if (geoJSONData) {
//            console.log(geoJSONData);
            saveToWikiPage(geoJSONData);
            saveButton.remove(); // saveButtonを非表示にする
        } else {
            alert('Error: Invalid GeoJSON data');
        }
    } else {
        alert('Please enable edit mode before saving.');
    }
}, '変更を保存');
 
 
 
 
function loadPinsFromWikiPage() {
    getMwToken()
        .then(function(token) {
            var geojsonPage = "<!--{$geojson}-->";
            var url = API_BASE_URL + '/api.php';
            console.log('Request URL:', url);
 
            return $.ajax({
                type: "GET",
                url: url,
                data: {
                    action: 'query',
                    titles: geojsonPage,
                    prop: 'revisions',
                    rvprop: 'content',
                    format: 'json',
                    // 明示的にwikiを指定
                    redirects: 0  // リダイレクトを防ぐ
                },
                headers: {
                    'Authorization': 'Bearer ' + token
                }
            });
        })
        .then(function(response) {
            try {
                // レスポンスからページコンテンツを取得
                const pages = response.query.pages;
                const pageId = Object.keys(pages)[0];
                const content = pages[pageId].revisions[0]['*'];
               
                // GeoJSONデータを抽出して処理
                const geoJSONData = JSON.parse(content);
                processGeoJSONData(geoJSONData);
             } catch (error) {
                console.error("Error processing data:", error);
                throw error;
            }
        })
        .catch(function(error) {
            console.error("Error loading data:", error);
            // より詳細なエラー情報を表示
            console.error('Detailed error:', {
                message: error.message,
                status: error.status,
                responseText: error.responseText
            });
         });
         });
}
function processGeoJSONData(geoJSON) {
    drawnItems.clearLayers();
    L.geoJSON(geoJSON, {
        pointToLayer: function (feature, latlng) {
            var iconType = feature.properties.iconType || 'icon1';
            var icon = iconDefinitions[iconType] || iconDefinitions.icon1;
           
            if (feature.properties.radius) {
                return L.circle(latlng, {
                    radius: feature.properties.radius,
                    tags: feature.properties.tags
                });
            } else {
                return L.marker(latlng, {
                    icon: icon,
                    tags: feature.properties.tags
                });
            }
        },
        onEachFeature: function (feature, layer) {
            var popupContent = '<strong>' + feature.properties.title + '</strong><br>' + feature.properties.content;
            layer.bindPopup(popupContent);
            layer.options.popupData = {
                title: feature.properties.title,
                content: feature.properties.content,
                iconType: feature.properties.iconType,
                tags: feature.properties.tags
            };
            createEditablePopup(layer);
            drawnItems.addLayer(layer);
        }
    });
}
 
//////////////////////////////////////////////////////////////////////////////
function convertToGeoJSON(drawnItems) {
    var geoJSON = {
        "type": "FeatureCollection",
        "features": []
    };
    drawnItems.eachLayer(function(layer) {
        var feature = layer.toGeoJSON();
        var popupData = layer.options.popupData || {};
        feature.properties = {
            title: popupData.title || '',
            content: popupData.content || '',
            iconType: popupData.iconType || 'icon1',
            tags: popupData.tags || [getTagFromIconType(popupData.iconType || 'icon1')]
        };
        if (layer instanceof L.Circle) {
            feature.properties.radius = layer.getRadius();
            feature.geometry = {
                type: "Point",
                coordinates: [layer.getLatLng().lng, layer.getLatLng().lat]
            };
        } else if (layer instanceof L.Marker) {
            feature.geometry = {
                type: "Point",
                coordinates: [layer.getLatLng().lng, layer.getLatLng().lat]
            };
        } else {
            // その他のタイプのレイヤーは無視する
            return;
        }
        geoJSON.features.push(feature);
    });
    // GeoJSONデータの有効性をチェック
    try {
        JSON.parse(JSON.stringify(geoJSON));
    } catch (error) {
        console.error("Invalid GeoJSON data:", error);
        return null;
     }
     }


     return JSON.stringify(geoJSON, null, 2); // 整形されたJSONを返す
    // スクリプトの順次読み込み
}
     return Promise.resolve()
 
        .then(() => loadScript('https://dq.h1g.jp/leaflet/widgetmap-core.js'))
 
         .then(() => loadScript('https://dq.h1g.jp/leaflet/widgetmap-icons.js'))
function getTagFromIconType(iconType) {
         .then(() => loadScript('https://dq.h1g.jp/leaflet/widgetmap-popups.js'))
    switch (iconType) {
         .then(() => loadScript('https://dq.h1g.jp/leaflet/widgetmap-api.js'))
        case 'icon1':
         .then(() => loadScript('https://dq.h1g.jp/leaflet/widgetmap-init.js'));
            return '<!--{$filter1|default:"分類1"}-->';
         case 'icon2':
            return '<!--{$filter2|default:"分類2"}-->';
         case 'icon3':
            return '<!--{$filter3|default:"分類3"}-->';
         case 'icon4':
            return '<!--{$filter4|default:"分類4"}-->';
         case 'icon5':
            return '<!--{$filter5|default:"分類5"}-->';
        case 'icon6':
            return '<!--{$filter6|default:"分類6"}-->';
        default:
            return '';
    }
}
}


  // フィルタボタンの定義
// Start loading when document is ready
 
$(document).ready(() => {
// Leaflet.Control.TagFilterButton の設定
     console.log('[Main] Starting initialization');
L.control.tagFilterButton({
    loadScriptsSequentially().catch(error => {
     data: [
         console.error('[Main] Loading sequence failed:', error);
        '<!--{$filter1|default:"分類1"}-->',
        alert('モジュールの読み込みに失敗しました。\n詳細はコンソールを確認してください。');
        '<!--{$filter2|default:"分類2"}-->',
        '<!--{$filter3|default:"分類3"}-->',
        '<!--{$filter4|default:"分類4"}-->',
        '<!--{$filter5|default:"分類5"}-->',
        '<!--{$filter6|default:"分類6"}-->'
    ],
    icon: '<img src="https://dq.h1g.jp/img/marker-icon-img/filter.png">',
    filterOnEveryClick: true
}).addTo(map);
 
 
// トークンを取得する関数
function getMwToken() {
    return new Promise((resolve, reject) => {
         $.ajax({
            url: API_BASE_URL + '/api.php',
            data: {
                action: 'query',
                meta: 'tokens',
                type: 'csrf',
                format: 'json'
            },
            type: 'GET',
            success: function(response) {
                if (response.query && response.query.tokens && response.query.tokens.csrftoken) {
                    resolve(response.query.tokens.csrftoken);
                } else {
                    reject(new Error('Failed to get token'));
                }
            },
            error: function(xhr, status, error) {
                reject(error);
            }
        });
     });
     });
}
function saveToWikiPage(geoJSONData) {
    var formattedData = geoJSONData;
   
    // 保存前に新しいトークンを取得
    getMwToken()
        .then(function(token) {
            return $.ajax({
                type: "POST",
                url: API_BASE_URL + '/api.php',
                data: {
                    action: 'edit',
                    title: '<!--{$geojson}-->',
                    text: formattedData,
                    token: token,
                    format: 'json'
                }
            });
        })
        .then(function(response) {
            if (response.edit && response.edit.result === 'Success') {
                alert('データは正常に保存されました');
                editMode = false;
                drawControl.remove();
                editButton.state('enable-edit');
                saveButton.remove();
               
                // 保存成功後、新しいトークンで再読み込み
                getMwToken()
                    .then(function(newToken) {
                        loadPinsFromWikiPage(newToken);
                    })
                    .catch(function(error) {
                        console.error("Failed to get token for reload:", error);
                    });
            } else {
                throw new Error('保存に失敗しました');
            }
        })
        .catch(function(error) {
            console.error("Save error:", error);
            alert('データの保存に失敗しました: ' + error.message);
        });
}
map.on(L.Draw.Event.CREATED, function (event) {
    var layer = event.layer;
    if (layer instanceof L.Marker) {
        layer.setIcon(iconDefinitions.icon1);
        layer.options.popupData = {title: '', content: '', iconType: 'icon1'};
    }
    createEditablePopup(layer);
    drawnItems.addLayer(layer);
});
////////////////////////////////////////////////////
// ページ読み込み時にデータを読み込む
$(document).ready(function() {
    setTimeout(function() {
        map.invalidateSize();
        // 初期読み込み時にトークンを取得してからデータを読み込む
        getMwToken()
            .then(function(token) {
                console.log('Initial token obtained');
                loadPinsFromWikiPage(token);
            })
            .catch(function(error) {
                console.error("Failed to get initial token:", error);
                alert('データの読み込みに失敗しました。ページを再読み込みしてください。');
            });
    }, 500);
});
});
</script>
</script>
</includeonly>
</includeonly>

2024年11月22日 (金) 02:17時点における最新版