图寻tips

需要特定地图才能提示,按Q键可以提示plonkit中的知识,比如:plonkit新手向等等,或者带有tips关键词的题库才能使用

当前为 2024-07-19 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         图寻tips
// @namespace    https://tuxun.fun/
// @version      4.7
// @description  需要特定地图才能提示,按Q键可以提示plonkit中的知识,比如:plonkit新手向等等,或者带有tips关键词的题库才能使用
// @supportURL   https://sleazyfork.org/en/scripts/480332-图寻tips
// @author       yukejun
// @match        https://tuxun.fun/*
// @grant        GM_xmlhttpRequest
// @connect      knowledgetips.fun
// @connect      nominatim.openstreetmap.org
// @license MIT
// ==/UserScript==
(function() {
    'use strict';
    // 在闭包中初始化 isMatch
let isMatch = true;
   //
// CSS样式
const modalStyles = `
#customModal {
    cursor: move;
    display: none;
    position: fixed;
    z-index: 1000;
    top: 10vh;
    left: 10vw;
    background-color: #fff;
    padding: 5px;
    border-radius: 10px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    width: 80vw;
    max-width: 350px;
    transform: translate(0, 0);
    text-align: left;
    opacity: 0;
    visibility: hidden;
    border: 0.5px solid #000;
    transition: opacity 0.4s ease, visibility 0.4s ease, transform 0.4s ease; /* 添加 max-height 到过渡效果中 */
}
/* 添加显示时的样式 */
#customModal.show {
    opacity: 1;
    visibility: visible;
    transform: translate(0, 10px); /* 添加轻微的向下移动效果以增强动态感 */
}
/* 鼠标悬停时的按钮样式 */
.modalButton {
    padding: 2px 5px;
    border: 1px solid #ccc;
    border-radius: 2px;
    cursor: pointer;
    transition: box-shadow 0.3s ease; /* 添加过渡效果 */
}
.modalButton:hover {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); /* 鼠标悬停时的阴影效果 */
}
#customModal * {
    user-select: text; /* 允许文本选择 */
    cursor: auto; /* 设置鼠标为默认样式 */
}
/* 特定元素,如按钮,可能需要重写这些样式 */
#customModal button {
    user-select: none; /* 防止按钮文本被选择 */
    cursor: pointer; /* 为按钮设置手型鼠标样式 */
}
#setTimeButton {
    background-image: url('https://pic1.zhimg.com/80/v2-7c700be8d7b319f5845121926faaae37_1440w.png');
    background-size: contain;
    background-repeat: no-repeat;
    border: none; /* 移除边框 */
    width: 18px; /* 根据需要调整尺寸 */
    height: 18px; /* 根据需要调整尺寸 */
    cursor: pointer; /* 鼠标悬停时显示手型光标 */
    position: absolute;
    top: 3px;
    right: 50px;
    background-color: #ffffff;
}
#customModalHeader {
    cursor: pointer;
    padding: 7px;
    background-color: #fff;
}
#customModalHeader h2 {
    font-size: 1.5em;
    margin: 0;
    color: #333;
    text-align: left;
}
#pinModal {
    background-image: url('https://pic1.zhimg.com/80/v2-0b6c9fb7436ac72d00ccc1f49a3919c0_1440w.webp'); /* 默认图钉图片 */
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center;
    color: transparent; /* 隐藏文本 */
    width: 21px; /* 设置合适的宽度 */
    height: 21px; /* 设置合适的高度 */
    position: absolute;
    top: 3px;
    right: 27px;
    background-color: #ffffff;
}
#modalContent {
    user-select: text;
    font-size: 16px;
    color: black;
    margin-top: 5px; /* 调整位置高度 */
    /* 根据需要,您也可以添加 margin-bottom */
}
#customInputBox {
    width: 90%;
    padding: 5px;
    margin: 10px 5%;
    border: 1px solid #ccc;
    border-radius: 5px;
    overflow-y: hidden;
    resize: none;
}
#modalClose {
    position: absolute;
    top: -4px;
    right: 8px;
    cursor: pointer;
    font-size: 1.5em;
    color: #333;
}
/* 响应式设计 */
@media (max-width: 600px) {
    #customModal {
        width: 95vw;
        left: 2.5vw;
        font-size: 14px;
    }
    #imageDisplay {
        width: 90%;
    }
    #customModalHeader {
        padding: 5px;
    }
}
@media (min-width: 601px) and (max-width: 800px) {
    #customModal {
        width: 70vw;
        left: 15vw;
        font-size: 16px;
    }
    #imageDisplay {
        width: 70%;
    }
}
/* 可以继续添加更多样式... */
/* 响应式设计 */
@media (max-width: 600px) {
    #customModal {
        width: 95vw;
        left: 2.5vw;
    }
}
#buttonGroup {
    display: flex;
    justify-content: center;
    gap: 5px;
    font-size: 14px;
}
.modalButton {
    padding: 5px 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
    cursor: pointer;
}
.centered-content {
    text-align: center;
    margin-bottom: 10px;
}
.locationSymbol {
    width: 20px;
    height: 25px;
    position: relative; /* 或者 'absolute',取决于您的需要 */
    top: 5px;  /* 向下移动5像素 */
    bottom: 5px; /* 向上移动5像素 */
    left: -5px; /* 向右移动10像素 */
}
#imageDisplay {
    width: 100%; /* 根据需要调整宽度 */
    margin-top: 10px;
    border-radius: 10px; /* 添加圆角 */
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); /* 添加阴影以增加深度感 */
    padding: 5px; /* 添加内边距 */
    background-color: #ffffff; /* 设定背景颜色 */
    transition: all 0.3s ease; /* 平滑过渡效果 */
}
.blankSpace {
    height: 5px; /* 您可以根据需要调整这个高度 */
    width: 100%;
}
.blankSpace1 {
    height: 5px; /* 您可以根据需要调整这个高度 */
    width: 100%;
}
.blankSpace2 {
    height: 5px; /* 您可以根据需要调整这个高度 */
    width: 100%;
}
.buttonActive {
    background-color: rgb(19, 206, 102); /* 浅绿色 */
    color: white;
}
.loader {
    border: 4px solid #3498db; /* 边框更细,整体为蓝色边框 */
    border-top: 3px solid #f3f3f3; /* 边框更细,顶部为轻色边框 */
    border-radius: 50%;
    width: 50px; /* 增大半径 */
    height: 50px; /* 增大半径 */
    animation: spin 2s linear infinite;
    margin: 0 auto; /* 水平居中 */
    display: block; /* 确保能够应用margin auto */
    margin-top: 25px; /* 增加顶部边距 */
}
@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}
`;
// HTML结构
const modalHTML = `
    <div id="customModal">
        <div id="customModalHeader">
            <h2>小技巧</h2>
            <div class="blankSpace1"></div> <!-- 新增的空白区域 -->
            <div id="buttonGroup" class="centered-content">
            <button class="modalButton" data-function="imagetip">Tips</button>
            <button class="modalButton" data-function="nationalflag">国旗</button>
            <button class="modalButton" data-function="areanumber">区编</button>
            <button class="modalButton" data-function="licensePlate">车牌</button>
            <button class="modalButton" data-function="text">文字</button>
            <button class="modalButton" data-function="tellphone">电话</button>
            </div>
            <div id="imageDisplayContainer">
            <img id="imageDisplay" src="" alt="显示图片" style="display:none;">
            </div>
            <div class="blankSpace"></div> <!-- 新增的空白区域 -->
            <button id="setTimeButton"></button>
            <button id="pinModal"></button>
            <div id="modalContent"></div>
            <textarea id="customInputBox" placeholder="在此输入内容..."></textarea>
        </div>
        <div style="text-align: center; margin-top: 10px;">
            <button id="addButton">新增</button>
        </div>
        <span id="modalClose">&times;</span>
    </div>
`;
    // 将CSS添加到页面
const styleSheet = document.createElement("style");
styleSheet.type = "text/css";
styleSheet.innerText = modalStyles;
document.head.appendChild(styleSheet);
    // 插入模态窗口到<body>的末尾
    document.body.insertAdjacentHTML('beforeend', modalHTML);
function updateModalPosition(x, y) {
    const modal = document.getElementById('customModal');
    modal.style.left = `${x}px`;
    modal.style.top = `${y}px`;
    localStorage.setItem('modalPosition', JSON.stringify({ x, y }));
}
function restoreModalPosition() {
    const modal = document.getElementById('customModal');
    const position = JSON.parse(localStorage.getItem('modalPosition'));
    if (position) {
        modal.style.left = `${position.x}px`;
        modal.style.top = `${position.y}px`;
    }
}
// 函数用于创建标签元素(段落和保存按钮)
function createTagElement(text, index) {
    // 创建一个 div 元素作为标签的外层容器
    const tagContainer = document.createElement('div');
    tagContainer.classList.add('tag-container'); // 添加类名以便应用CSS样式
    // 创建一个 div 元素来容纳标签的内容(编号和文本)
    const tagContentContainer = document.createElement('div');
    tagContentContainer.classList.add('tag-content-container'); // 添加类名
    // 创建一个 span 元素作为标签编号的容器
    const label = document.createElement('span');
    label.textContent = index !== undefined ? `${index + 1}. ` : ''; // 如果提供了 index,则显示编号
    label.classList.add('tag-label'); // 添加类名
    // 创建一个段落元素用于显示传入的文本
    const paragraph = document.createElement('p');
    paragraph.textContent = text; // 设置段落文本
    paragraph.contentEditable = false; // 设置为不可编辑
    paragraph.id = index !== undefined ? `tag-${index}` : undefined; // 如果提供了 index,则设置ID
    // 创建一个占位元素,用于在需要时占据保存按钮的空间
    const placeholder = document.createElement('div');
    placeholder.style.display = 'none'; // 初始状态隐藏
// 创建一个新的按钮元素
const saveButton = document.createElement('button');
// 设置按钮的文本内容为'保存'
saveButton.textContent = '保存';
// 给按钮添加一个CSS类名'save-button'
saveButton.classList.add('save-button');
// 根据index变量的值设置按钮的点击事件处理函数
saveButton.onclick = index !== undefined ?
    () => {
        saveTag(paragraph, index); // 如果index已定义,调用saveTag函数并传递paragraph和index参数
        saveButton.style.display = 'none'; // 点击后使按钮消失
    } :
    () => {
        saveTag(paragraph); // 如果index未定义,只调用saveTag函数并传递paragraph参数
        saveButton.style.display = 'none'; // 点击后使按钮消失
    };
// 设置按钮的初始显示状态为隐藏
saveButton.style.display = 'none';
    // 应用保存按钮的样式
    applyButtonStyles(saveButton);
    // 设置段落的双击事件处理函数
    // 使段落在双击时变为可编辑,并显示保存按钮和占位元素
    let isEditable = false; // 发布时需要更改的代码
    paragraph.ondblclick = function() {
        if (isEditable) {
            makeEditable(paragraph, saveButton, placeholder);
        }
        // 如果 isEditable 为 false,则不执行任何操作
    };
    // 从本地存储中获取创建者名称
    const creatorName = localStorage.getItem('creatorName');
    // 创建一个新段落来显示创建者信息
    const creatorParagraph = document.createElement('p');
    creatorParagraph.textContent = `${creatorName}`;
    creatorParagraph.classList.add('creator-info'); // 添加类名
    creatorParagraph.style.fontSize = '10px'; // 设置字体大小
    creatorParagraph.style.color = 'black'; // 设置字体颜色
    creatorParagraph.style.marginLeft = '60px'; // 设置左边距
    // 在段落旁边添加标签元素
    tagContentContainer.appendChild(label);
    tagContentContainer.appendChild(paragraph);
    tagContainer.appendChild(placeholder);
    tagContainer.appendChild(tagContentContainer);
    tagContainer.appendChild(creatorParagraph);
    tagContainer.appendChild(saveButton);
    return tagContainer;
}
// 函数使段落变为可编辑并显示保存按钮
function makeEditable(paragraph, saveButton, placeholder) {
    paragraph.contentEditable = "true";
    paragraph.focus(); // 立即聚焦到段落,方便编辑
    saveButton.style.display = 'inline-block'; // 显示保存按钮
    placeholder.style.display = 'block'; // 显示占位元素
}
// 应用按钮样式的函数
function applyButtonStyles(button) {
        // 使用响应式设计,例如min-width和min-height,以适应不同屏幕尺寸
    button.style.minWidth = '50px';
    button.style.minHeight = '25px';
    button.style.overflow = 'hidden'; // 防止内容溢出
    button.style.backgroundColor = '#4CAF50'; // 绿色背景
    button.style.color = 'white'; // 白色文字
    button.style.border = 'none'; // 无边框
    button.style.borderRadius = '5px'; // 圆角
    button.style.padding = '5px 5px'; // 内边距
    button.style.cursor = 'text'; // 鼠标悬停时的手指图标
    // 悬浮效果
    button.onmouseover = function() {
        button.style.backgroundColor = '#45a049'; // 深绿色
    };
    button.onmouseout = function() {
        button.style.backgroundColor = '#4CAF50'; // 原绿色
    };
}
    // 创建一个style元素并添加CSS
    function addCustomStyles() {
        const style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = `
        .tag-container {
            display: flex;
            flex-direction: column;
            align-items: flex-end; // 所有子元素向右对齐
            margin-bottom: 10px;
            high: 110%
        }
        .tag-content-container {
            cursor: auto;
            display: flex;
            align-items: center; // 内部元素水平对齐
            flex-grow: 1;
            width: 100%; // 占满整个容器宽度
        }
        .tag-label {
            cursor: auto;
            margin-right: 8px;
            font-weight: bold;
            align-self: flex-start; // 标签向左上角对齐
        }
        .tag-container p {
            cursor: auto;
            margin: 0;
            margin-right: 8px;
            flex-grow: 1; // 让段落填满剩余空间
        }
        .save-button {
            display: none;
        }
        .creator-info {
            cursor: auto;
            align-self: flex-end; // 向右对齐
        }
        @media (max-width: 600px) {
            .save-button {
                // 小屏幕上的特定样式
                min-width: 30px;
                min-height: 10px;
                align-self: flex-end; // 向右对齐
            }
        }
    `;
        document.head.appendChild(style);
    }
window.onload = function() {
    // 获取所有的 .creator-info 元素
    var creatorInfoElements = document.querySelectorAll('.creator-info');
    let isPageFirstLoad = localStorage.getItem('isPageFirstLoad') !== 'false';
    if (isPageFirstLoad) {
        // 这里是第一次加载页面时需要执行的代码
        const storedTagsText = localStorage.getItem('tagsText');
        const storedImageUrls = JSON.parse(localStorage.getItem('imageUrls') || '[]');
        if (storedTagsText) {
            let modalContent = storedTagsText;
            showModal(modalContent); // 显示模态窗口
        }
        localStorage.setItem('isPageFirstLoad', 'false');
    }
    // 遍历所有元素并直接设置其样式
    creatorInfoElements.forEach(function(elem) {
        elem.style.fontSize = '14px'; // 设置字体大小
        elem.style.color = '#333333'; // 设置字体颜色
    });
};
const customInputBox = document.getElementById('customInputBox');
customInputBox.addEventListener('keyup', function(event) {
    adjustTextareaHeight(this);
});
    function adjustTextareaHeight(textarea) {
        textarea.style.height = 'auto'; // 重置高度
        textarea.style.height = textarea.scrollHeight + 'px'; // 根据内容调整高度
    }
// 函数用于激活模态窗口时阻止键盘事件传播
function preventKeyPropagation() {
    const modal = document.getElementById('customModal');
    modal.addEventListener('keydown', function(event) {
        event.stopPropagation(); // 阻止事件冒泡到父元素
        // 如果需要,也可以根据需求阻止默认行为
        // event.preventDefault();
    });
}
        // 在页面加载时调用函数以添加样式
window.addEventListener('load', function() {
        addCustomStyles(); // 添加自定义样式
        preventKeyPropagation(); // 防止键盘事件传播
        // 尝试从 localStorage 中获取模态窗口的位置
        const savedPosition = localStorage.getItem('modalPosition');
        if (savedPosition) {
        const { x, y } = JSON.parse(savedPosition);
        const modal = document.getElementById('customModal');
        if (modal) {
            // 设置模态窗口的位置
            modal.style.left = x + 'px';
            modal.style.top = y + 'px';
        }
    }
    //发布时需要添加的代码
    document.getElementById('addButton').style.display = 'none';
    document.getElementById('customInputBox').style.display = 'none';
    });
// 为 setTimeButton 按钮添加点击事件监听器
document.getElementById('setTimeButton').addEventListener('click', function() {
    event.stopPropagation()
    // 弹出一个对话框让用户输入新的倒计时时间
    let newTime = prompt("请输入新的倒计时时间(秒),时间必须是 3 秒或以上的正整数:");
    // 如果用户点击取消,newTime 将是 null,不执行任何操作
    if (newTime === null) {
        return;
    }
    // 验证输入是否为正整数且大于等于 3
    if (!isNaN(newTime) && Number.isInteger(parseFloat(newTime)) && parseInt(newTime) >= 3) {
        // 更新倒计时时间
        countdownTime = parseInt(newTime);
        // 将新的倒计时时间存储在 localStorage 中
        localStorage.setItem('countdownTime', countdownTime);
        // 可以在这里重新开始倒计时或者进行其他操作
    } else {
        alert("请输入有效的正整数(3秒或以上)!");
    }
});
// 全局变量,控制是否显示图片
let shouldDisplayImage = false;
let countdownTime = 30; // 默认倒计时时间为3秒
let countdownInterval; // 将倒计时定时器声明为全局变量
let immediateDisplay = false; // 新增一个全局变量来控制是否立即显示文本内容
// 从localStorage获取倒计时时间
function getStoredCountdownTime() {
    const storedCountdown = localStorage.getItem('countdownTime');
    if (storedCountdown !== null) {
        countdownTime = parseInt(storedCountdown, 10);
    }
}
// 显示模态窗口并在15秒内进行倒计时
function showModal(serverText) {
 //
    // 重置immediateDisplay为false
    immediateDisplay = false;
    // 获取存储的倒计时时间
    getStoredCountdownTime();
    const modal = document.getElementById('customModal');
    const modalContent = document.getElementById('modalContent');
    // 清空modalContent的内容
    modalContent.innerHTML = '倒计时: 15秒';
// 获取存储在 localStorage 中的各个地址组件
const storedAddress = localStorage.getItem('address');
const storedState = localStorage.getItem('state');
const storedRegion = localStorage.getItem('region');
const storedCity = localStorage.getItem('city');
const displayAddress = storedAddress || storedState || storedRegion || storedCity || '地址信息未找到';
//
const storedModalPosition = JSON.parse(localStorage.getItem('modalPosition'));
const storedImageUrl = localStorage.getItem('savedImageUrl');
if (storedModalPosition) {
    modal.style.left = storedModalPosition.x + 'px';
    modal.style.top = storedModalPosition.y + 'px';
}
    // 如果之前的倒计时仍在运行,则清除它
    if (countdownInterval) {
        clearInterval(countdownInterval);
    }
    // 初始化倒计时
    let countdown = countdownTime;
    // 设置一个每秒更新一次的定时器
    countdownInterval = setInterval(function() {
        if (immediateDisplay) {
            // 如果需要立即显示文本内容
            clearInterval(countdownInterval);
            displayContent(serverText, displayAddress);
            shouldDisplayImage = true;
        } else {
            countdown--;
           modalContent.innerHTML = `<p style="text-align: center; font-size: 18px; margin-top: 48px; position: relative; top: -20px;">倒计时: ${countdown}秒</p>`;
            // 当倒计时结束时
        if (countdown <= 0) {
            clearInterval(countdownInterval);
            displayContent(serverText, displayAddress);
            shouldDisplayImage = true;
        }
        }
    }, 1000);
    // 清空modalContent的内容
    modalContent.innerHTML = '<div class="loader"></div><p></p>';
   // 显示模态窗口
if (modal.style.display === 'none') {
    modal.style.display = 'block';
    modal.style.opacity = '1';
    modal.style.visibility = 'visible';
}
const wrapperElement = document.querySelector('.wrapper___NMMQn');
    if (wrapperElement) {
    const observer = new MutationObserver(function(mutations, obs) {
    const canvasElement = wrapperElement.querySelector('.mapConfirm___Q8fp1');
    if (canvasElement) {
    } else {
        skipCountdown();
        obs.disconnect();

    }
});
        observer.observe(wrapperElement, { childList: true, subtree: true });
    }else {
        console.log('wei找到选择器wrapper');
    }

}
// 显示最终内容的函数
function displayContent(serverText, displayAddress) {
    const locationSymbolHtml = `<img
    src="https://pic1.zhimg.com/80/v2-b5108764f32666bde67f8e7340b3350c_r.jpg"
alt="Location" class="locationSymbol" />`;
    modalContent.innerHTML = `<p>${locationSymbolHtml} ${displayAddress}</p>`;
    // 显示解析后的serverText内容
    const tags = serverText.split('; ');
    tags.forEach((tag, index) => {
        const tagElement = createTagElement(tag, index);
        modalContent.appendChild(tagElement);
    });
}
// 在需要的时候可以调用这个函数来立即显示文本内容
function skipCountdown() {
    immediateDisplay = true;
}
    // 关闭模态窗口的函数
    function closeModal() {
        const modal = document.getElementById('customModal');
        modal.style.opacity = '0';
        modal.style.visibility = 'hidden';
        setTimeout(() => modal.style.display = 'none', 100); // 确保过渡效果结束后再隐藏
    }
    //更新标签
function updateTagNumbers() {
    const tags = document.querySelectorAll('.tag-container');
    tags.forEach((tag, index) => {
        const label = tag.querySelector('.tag-label');
        if (label) {
            label.textContent = `${index + 1}. `;
        }
    });
}
// 全局变量
let isSaveTagActive = true; // 控制函数是否激活
// 函数保存编辑后的标签并发送数据到服务器
function saveTag(paragraph, index) {
    // 如果全局变量为 false,则函数不执行任何操作
    if (!isSaveTagActive) {
        return;
    }
    // 获取并处理编辑后的文本
    const editedText = paragraph.textContent.trim();
    paragraph.contentEditable = "false"; // 关闭可编辑状态
    // 从localStorage获取当前标签列表
    let tags = localStorage.getItem('tagsText') ? localStorage.getItem('tagsText').split('; ') : [];
    // 更新或移除标签
    if (index !== undefined) {
        if (editedText === '') {
            // 用户删除了所有文本,从标签数组中移除该标签
            tags.splice(index, 1);
if (editedText === '') {
    tags.splice(index, 1); // 从标签数组中移除该标签
    // 从 DOM 中移除标签元素及其内部元素
    const tagContainer = paragraph.parentElement.parentElement;
    if (tagContainer) {
        tagContainer.remove();
        updateTagNumbers(); // 更新标签编号
    }
}
        } else {
            // 更新指定索引的标签
            tags[index] = editedText;
        }
    } else if (editedText !== '') {
        // 添加新标签时,追加到标签数组的末尾
        tags.push(editedText);
    }
    // 过滤和更新标签列表
    tags = tags.filter(tag => tag && tag.trim());
    const updatedTagsText = tags.join('; ');
    localStorage.setItem('tagsText', updatedTagsText);
const storedCoordinates = JSON.parse(localStorage.getItem('newCoordinateName'));
    // 准备发送的数据
    const dataToSendtext = {
        mapsId: localStorage.getItem('mapsId'),
        coordinates: storedCoordinates,
        tagsText: updatedTagsText
    };
    // 隐藏保存按钮
    const saveButton = paragraph.parentElement.querySelector('.save-button');
    if (saveButton) {
        saveButton.style.display = 'none';
    }
}
//发布时添加
isSaveTagActive = false; // 关闭
isSaveTagActive = true;  // 开启
// 验证输入内容的函数
function isValidInput(input) {
    const maxLength = 300; // 最大字符长度设置为300
    // 检查长度
    if (input.length > maxLength) {
        alert(`输入的文本太长,请输入不超过 ${maxLength} 个字符的文本。`);
        return false;
    }
    return true;
}
// 新增标签的函数
function addNewTag() {
    //
    const inputBox = document.getElementById('customInputBox');
    const newText = inputBox.value.trim();
    if (newText && isValidInput(newText)) {
        const newTagElement = createTagElement(newText);
        const modalContent = document.getElementById('modalContent');
        modalContent.appendChild(newTagElement);
        // 保存新标签并发送到服务器
        saveTag(newTagElement.querySelector('p'));
        inputBox.value = '';
        // 更新所有标签的序号
        updateTagNumbers();
    }
    inputBox.value = ''; // 清空输入框
    // 重置文本框的高度
    const customInputBox = document.getElementById('customInputBox');
    customInputBox.style.height = '30px'; // 设置为初始高度或任意合适的固定高度
}
// 给新增按钮添加点击事件监听器
const addButton = document.getElementById('addButton');
    if (addButton) {
   //
} else {
  //
}
addButton.addEventListener('click', addNewTag);
// 置顶状态追踪变量
let isPinned = false;
// 从localStorage读取置顶状态
function loadPinState() {
    // 尝试从localStorage获取之前保存的状态
    const savedState = localStorage.getItem('isPinned');
    if (savedState !== null) {
        // 更新isPinned变量为保存的状态(需要将字符串转换为布尔值)
        isPinned = savedState === 'true';
    }
    // 更新按钮的显示
    updatePinButton();
}
// 更新置顶按钮的显示
function updatePinButton() {
    const pinButton = document.getElementById('pinModal');
    if (isPinned) {
        pinButton.style.backgroundImage = "url('https://pic1.zhimg.com/80/v2-0b6c9fb7436ac72d00ccc1f49a3919c0_1440w.webp')";
    } else {
        pinButton.style.backgroundImage = "url('https://pic2.zhimg.com/80/v2-893d2c6777c1205430e5fa2cc4019ae9_1440w.webp')";
    }
}
// 切换置顶状态的函数
function togglePin() {
    isPinned = !isPinned;
    // 保存当前状态到localStorage
    localStorage.setItem('isPinned', isPinned);
    // 更新按钮的显示
    updatePinButton();
}
// 添加置顶按钮的事件监听器
document.getElementById('pinModal').addEventListener('click', function(event) {
    togglePin();
    event.stopPropagation(); // 阻止事件冒泡到document,防止触发关闭模态窗口的逻辑
});
// 当页面加载时,读取并显示之前保存的置顶状态
window.addEventListener('load', loadPinState);
//以上是置顶函数变量
let isDragging = false;
let dragStartX, dragStartY;
let originalX, originalY;
document.getElementById('customModalHeader').addEventListener('mousedown', function(e) {
    if (e.target !== this && e.target !== document.querySelector('#customModalHeader h2')) {
        return;
    }
    isDragging = true;
    dragStartX = e.clientX;
    dragStartY = e.clientY;
    const modal = document.getElementById('customModal');
    originalX = parseInt(window.getComputedStyle(modal).left, 10);
    originalY = parseInt(window.getComputedStyle(modal).top, 10);
    e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
    if (!isDragging) return;
    let newX = originalX + e.clientX - dragStartX;
    let newY = originalY + e.clientY - dragStartY;
    updateModalPosition(newX, newY);
});
document.addEventListener('mouseup', function(e) {
    if (isDragging) {
        isDragging = false;
        let newX = originalX + e.clientX - dragStartX;
        let newY = originalY + e.clientY - dragStartY;
        updateModalPosition(newX, newY);
                // 存储新位置到 localStorage
        localStorage.setItem('modalPosition', JSON.stringify({ x: newX, y: newY }));
    }
});
    // 点击模态窗口以外的区域关闭模态窗口
// 修改点击模态窗口以外区域关闭模态窗口的逻辑,加入置顶状态判断
document.addEventListener('click', function(event) {
    const modal = document.getElementById('customModal');
    // 如果模态窗口未被置顶,并且点击的不是模态窗口也不是模态窗口的子元素,则关闭模态窗口
    if (!isPinned && !modal.contains(event.target)) {
        closeModal();
    }
});

    document.getElementById('modalClose').addEventListener('click', closeModal);

    function toggleModal() {
        const modal = document.getElementById('customModal');
        if (modal.style.opacity === '1' || modal.style.visibility === 'visible') {
            modal.style.opacity = '0';
            modal.style.visibility = 'hidden';
            modal.style.display = 'none';
        } else {
            modal.style.opacity = '1';
            modal.style.visibility = 'visible';
            modal.style.display = 'block';
        }
    }
var shouldSend = true; 

    document.addEventListener("keyup", function(evt) {
        const targetTagName = (evt.target || evt.srcElement).tagName;
        if (evt.key === 'q' && targetTagName !== 'INPUT' && targetTagName !== 'TEXTAREA') {
            toggleModal();
       // 改变发送状态 shouldSend = !shouldSend;
        }
    });

    const mapsIdPattern = /mapsId=(\d+)|\/map\/(\d+)/;

const addressPattern = /\[\s*null,\s*null,\s*\[\s*(\[\s*"([^"]*)",\s*"([^"]*)"\s*\])(,\s*\[\s*"([^"]*)",\s*"([^"]*)"\s*\])?\s*\]\s*\]/;
    // 合并的正则表达式,用于匹配两种不同类型的坐标
const coordinatePattern = /\[\[null,null,(-?\d+\.\d+),(-?\d+\.\d+)\],\[\d+\.\d+\],\[\d+\.\d+,\d+\.\d+,\d+\.\d+\]\]|\[\s*null,\s*null,\s*(-?\d+\.\d+),\s*(-?\d+\.\d+)\s*\]|"lat":\s*(-?\d+\.\d+),\s*"lng":\s*(-?\d+\.\d+)/;
  // 保存原始的send方法
try {
    // 检查shouldSend变量
    if (shouldSend) {
        // 在发送请求之前保存请求的URL
    let currentUrl = this._url;
    // 初始化mapsIdChanged变量为false
    // 添加一个事件监听器来处理请求加载完成后的逻辑
    this.addEventListener("loadstart", function() {
        currentUrl = this._url; // 保存实际发送时的URL
// 当请求完成时检查URL
this.addEventListener("load", function() {
    // 从localStorage获取当前和之前的mapsId
    let previousMapsId = localStorage.getItem('previousMapsId');
    let currentMapsId = localStorage.getItem('mapsId');
    // 检查URL是否包含mapsId,如果不包含则从响应中获取
   if (this._url.includes('https://tuxun.fun/api/v0/tuxun/solo/get?gameId')) {
        var response = JSON.parse(this.responseText);
                    try {
    // 提取并打印 mapsId 字段
    if (response && response.data && response.data.mapsId !== undefined) {
        const newMapsId = response.data.mapsId;
        if (newMapsId !== currentMapsId) {
                localStorage.setItem('previousMapsId', currentMapsId);
                localStorage.setItem('mapsId', newMapsId);
        }

    } else {
        console.error("没找到");
    }
            } catch (error) {
                console.error("Error parsing JSON response:", error);
            }
    }

            // 在发布时需要删除这段代码,从URL中提取新的mapsId
if (currentUrl.includes('https://tuxun.fun/api/v0/tuxun/mapProxy/getGooglePanoInfoPost') ||
    currentUrl.includes('https://tuxun.fun/api/v0/tuxun/mapProxy/getPanoInfo?pano=')) {
        //
// 定义isCountryCode函数
function isCountryCode(str) {
    return /^[A-Za-z]{2}$/.test(str);
}
const responseText = this.responseText;
let addressMatches;
let isAddressFound = false;
let loopCount = 0;
let address;
while ((addressMatches = addressPattern.exec(responseText)) !== null && loopCount < 3) {
    loopCount++;

    if (addressMatches[5] && !isCountryCode(addressMatches[5])) {
        address = addressMatches[5];
        isAddressFound = true;

    }

    else if (addressMatches[2] && !isCountryCode(addressMatches[2])) {
        address = addressMatches[2];
        isAddressFound = true;
      //
    }
    if (isAddressFound) {

        break; 
    } else {
      //
    }
}
if (!isAddressFound) {
 //
}

if (isAddressFound) {
    const storedAddress = localStorage.getItem('address');
    if (address !== storedAddress) {
        localStorage.setItem('address', address);
    } else {
    }
} else {
    localStorage.removeItem('address');
}

if (coordinatePattern.test(responseText)) {

let latitude, longitude;
const matches = coordinatePattern.exec(responseText);
if (matches) {

    if (matches[1] !== undefined && matches[2] !== undefined) {
        latitude = matches[1];
        longitude = matches[2];
          }

    else if (matches[3] !== undefined && matches[4] !== undefined) {
        latitude = matches[3];
        longitude = matches[4];
      //
    }

    else if (matches[5] !== undefined && matches[6] !== undefined) {
        latitude = matches[5];
        longitude = matches[6];
            }
    if (latitude !== undefined && longitude !== undefined) {
let storedCoordinates = null 
const storedCoordinatesString = localStorage.getItem('newCoordinateName');
if (storedCoordinatesString) {

    try {
        if (storedCoordinatesString !== "null") {
            storedCoordinates = JSON.parse(storedCoordinatesString);

        }
    } catch (e) {
        console.error('解析存储的坐标时发生错误,使用默认坐标: ', e);
    }
}
const tolerance = 0.005;
let isWithinTolerance = true;
function isCoordinateCloseEnough(storedCoordinates, latitude, longitude, tolerance) {
    if (!storedCoordinates) {
        return true;
    }
    const latDifference = Math.abs(storedCoordinates.latitude - latitude);
    const lonDifference = Math.abs(storedCoordinates.longitude - longitude);
    if (latDifference > tolerance || lonDifference > tolerance) {
        isWithinTolerance = true; // 坐标不在容差范围内,设置isMatch为true
    } else {
        isWithinTolerance = false; // 坐标在容差范围内,设置isMatch为false
    }
    return isMatch;
}
function processIfCoordinateChanged(storedCoordinates, latitude, longitude) {
    if (isCoordinateCloseEnough(storedCoordinates, latitude, longitude, tolerance)) {
        const newCoordinates = { latitude: latitude, longitude: longitude };
        localStorage.setItem('newCoordinateName', JSON.stringify(newCoordinates));
        localStorage.removeItem('tagsText');
        localStorage.removeItem('state');
        localStorage.removeItem('address');
        getAddressAndProcessData(latitude, longitude);
        shouldDisplayImage = false;
        clearImageDisplay()
    } else {

    }
}
processIfCoordinateChanged(storedCoordinates, latitude, longitude)

function getAddress(lat, lon) {
    return new Promise((resolve) => {
        try {
            GM_xmlhttpRequest({
                method: "GET",
                url: `https://www.123.com`,
                onload: function(response) {
                   //
                    if (response.status === 200) {
                       //
                        resolve(JSON.parse(response.responseText));
                    } else {
                        resolve({ error: `无法获取地址。状态码: ${response.status}`, lat, lon }); // 使用 resolve 代替 reject
                    }
                },
                onerror: function(error) {

                    resolve({ error: "在获取地址时发生错误", lat, lon }); // 使用 resolve 代替 reject
                }
            });
        } catch (error) {

            resolve({ error: "在获取地址时发生异常", lat, lon }); // 使用 resolve 代替 reject
        }
    });
}

function checkAndSendRequest() {

    if (isMatch && isWithinTolerance) {
        sendRequest();
    }
}
function getAddressAndProcessData(latitude, longitude) {

    getAddress(latitude, longitude)
        .then(addressData => {
            if (addressData) {
                ['country', 'state', 'region', 'city'].forEach(key => {
                    processAddressData(addressData, key);
                });
            } else {
            }

checkAndSendRequest();

window.checkAndSendRequest = checkAndSendRequest;
    })
    .catch(errorData => {
        // 此处可以继续使用 errorData.lat 和 errorData.lon
    });
}

function processAddressData(data, key) {
    if (data && data.address && data.address[key]) {
        const value = data.address[key].split('/')[0].trim();
        const storedValue = localStorage.getItem(key);
        localStorage.setItem(key, value);
        // 如果 country 信息相同,则清除 localStorage 中的 country 信息
/*        if (key === 'country' && storedValue === value) {
            localStorage.removeItem(key);
        } else if (storedValue !== value) {
            // 对于 country 以外的信息,或者 country 信息不同,更新 localStorage
          //
            localStorage.setItem(key, value);
        }
*/
    } else {
    }
}
// 初始化一个变量来跟踪重试次数
let retryCount = 0;
    function sendRequest() {
                    const mapsId = localStorage.getItem('mapsId');
                    const country = localStorage.getItem('country');
                    // 定义将要发送的数据
                    const dataToSend = JSON.stringify({ mapsId, coordinates: `${latitude},${longitude}`,country });
                    // 使用GM_xmlhttpRequest发送坐标和mapsId到指定的服务器地址
                    GM_xmlhttpRequest({
                        method: "POST",
                        url: 'http://knowledgetips.fun:3000/receive-data',
                        data: JSON.stringify({ mapsId, coordinates: `${latitude},${longitude}`,country }),
                        headers: {
                            "Content-Type": "application/json"
                        },
onload: function(response) {
   //
    if (response && response.responseText) {
        try {
            const jsonResponse = JSON.parse(response.responseText);
            handleResponse(response);
        } catch (error) {
            console.error('解析响应时出错:', error);
            console.error('原始响应文本:', response.responseText);
        }
    } else {
        console.error('响应文本不存在或为空');
    }
},
    onerror: function(error) {
        // 检查是否已达到最大重试次数
        if (retryCount < 3) {
            retryCount++;
            setTimeout(sendRequest, 1000); // 1秒后重新发送请求
        } else {
        }
    },
                    });
}
function handleResponse(response) {
    try {
        const jsonResponse = JSON.parse(response.responseText);
        // 处理 jsonResponse
        processResponseData(jsonResponse);
        storeResponseData(jsonResponse);
        updateIsMatch(jsonResponse);
        updateButtonStates(jsonResponse);
    } catch (error) {
        console.error("解析JSON失败:", error);
    }
}
function storeResponseData(jsonResponse) {
    // 检查响应中是否包含 creator 字段
    if (jsonResponse.hasOwnProperty('creator')) {
        const creatorName = jsonResponse.creator;
        localStorage.setItem('creatorName', creatorName); // 将 creator 字段的内容存储在 localStorage 中
      //
    }
    // 检查响应中是否包含 images 字段
    if (jsonResponse.hasOwnProperty('images')) {
        const images = jsonResponse.images;
        localStorage.setItem('images', JSON.stringify(images)); // 将 images 字段的内容以字符串形式存储在 localStorage 中
      //
        // 检查是否存在 imagetip 键,并单独存储
        if (images.hasOwnProperty('imagetip')) {
            const imagetip = images.imagetip;
            localStorage.setItem('imagetip', imagetip); // 单独存储 imagetip 字段的内容
          //
        }
    }
}
function updateIsMatch(jsonResponse) {
        // 根据响应中的 mymapsid 值更新 isMatch 变量
        if (jsonResponse.hasOwnProperty('mymapsid')) {
            isMatch = jsonResponse.mymapsid;
        }
}
// ***********************控制按钮的颜色***********************  //
function updateButtonStates(jsonResponse) {
    const buttonContainer = document.getElementById('buttonGroup');
    const buttons = buttonContainer.querySelectorAll('button');
    // 首先,从所有按钮中移除 'buttonActive' 类
    buttons.forEach(button => button.classList.remove('buttonActive'));
    for (const key in jsonResponse.images) {
      //
        if (jsonResponse.images[key]) {
            const button = buttonContainer.querySelector(`button[data-function="${key}"]`);
            if (button) {
                button.classList.add('buttonActive');
               //
            } else {
             //
            }
        } else {
          //
        }
    }
}
// ***********************控制按钮的颜色***********************  //
function processResponseData(jsonResponse, coordinates) {
    if (jsonResponse.match === false) {
        return;
    }
    if (jsonResponse.match && jsonResponse.tags && jsonResponse.tags.join('; ').length >= 6) {
        // 将标签数组转换为文本并存储在localStorage中
        const tagsText = jsonResponse.tags.join('; ');
        // 更新模态窗口内容
        const modal = document.getElementById('customModal');
        if (modal.style.display !== 'none') {
            const modalContent = document.getElementById('modalContent');
            modalContent.textContent = tagsText; // 更新模态窗口内容
        }
        // 显示模态窗口
        localStorage.setItem('tagsText', tagsText);
        localStorage.setItem('coordinates', JSON.stringify(coordinates));
        showModal(tagsText);
    } else {
        skipCountdown()
        showModal('无提示');
    }
}
const customInputBox = document.getElementById('customInputBox');
function updateImagesDict() {
        // 检查是否在customInputBox中
    if (document.activeElement === customInputBox) {
       //
        return;
    }
        // 如果shouldDisplayImage为false,则不执行任何操作
    if (!shouldDisplayImage) {
       //
        return;
    }
    // 尝试从localStorage获取images字段
    const storedImages = localStorage.getItem('images');
 //
    let imagesDict = {};
    if (storedImages) {
        try {
            // 将存储的字符串转换为对象
            imagesDict = JSON.parse(storedImages);
        } catch (error) {
            console.error("解析images失败:", error);
        }
    }
    return imagesDict;
}
// 创建或获取img标签的函数
function getOrCreateImageTag() {
    let imgTag = document.getElementById('uniqueImageId');
    if (!imgTag) {
        imgTag = document.createElement('img');
        imgTag.id = 'uniqueImageId';
        // 设置样式
        Object.assign(imgTag.style, {
            height: "80vh", // 高度为视口高度的80%
            width: 'auto',
            backgroundColor: 'white',
            position: 'absolute',  // 绝对定位
            left: '30%',  // 水平居中
            top: '46%',  // 垂直居中
            transform: 'translate(-50%, -50%)',  // 用于确保准确居中
            zIndex: 1200, // 高层级
            display: 'none'  // 默认不显示图片
        });
        document.body.appendChild(imgTag);
    }
    return imgTag;
}
// 用于显示或隐藏图片的函数
function displayImage(fieldName, fieldKey) {
        // 如果shouldDisplayImage为false,则不执行任何操作
    // 每次调用时都从localStorage获取最新的imagesDict
    const imagesDict = updateImagesDict();
        // 在适当的时机调用 setupModalListener
    // 当imagesDict为空时,不执行任何操作
 try {
    if (Object.keys(imagesDict).length === 0) {
        return;
    }
        let imgTag;
        if (['1', '2', '3', '4', '5', '6'].includes(fieldKey)) {
            imgTag = document.getElementById('imageDisplay');
        } else {
            imgTag = getOrCreateImageTag();
        }
        // 检查imagesDict是否包含fieldName对应的项
        if (imgTag && imagesDict.hasOwnProperty(fieldName)) {
            if (imgTag.style.display === 'none' || imgTag.src !== imagesDict[fieldName]) {
                imgTag.src = imagesDict[fieldName];
                imgTag.style.display = 'block';
            } else {
                imgTag.style.display = 'none';
            }
        } else {
        }
    } catch (error) {
       // console.error(`显示图片时发生错误: ${error.message}`);
    }
}
function clearImageDisplay() {
    const imgTag = document.getElementById('imageDisplay');
    if (imgTag) {
        imgTag.style.display = 'none';  // 隐藏图片容器
      //
    } else {
    }
}
// 仅在必要时添加事件监听器
function setupEventListener() {
    const imagesDict = updateImagesDict();
    const existingListener = document.getElementById('imageDisplayListener');
    if (!existingListener) {
        const listenerTag = document.createElement('span');
        listenerTag.id = 'imageDisplayListener';
        document.body.appendChild(listenerTag);
        document.addEventListener('keyup', function(event) {
            const fieldKeyMap = {
                '1': 'imagetip',
                '2': 'nationalflag',
                '3': 'areanumber',
                '4': 'licensePlate',
                '5': 'text',
                '6': 'tellphone',
                'e': 'mapjpg',
                'r': '3dmap',
                't': 'climateimg'
            };
            const fieldKey = event.key;
            const fieldName = fieldKeyMap[fieldKey];
            if (fieldName) {
             //
                displayImage(fieldName, fieldKey, imagesDict);
            } else {
              //
            }
        });
    }
}
/****************************以下这段代码有bug不知道怎么解决,
就是在点击事件中,总会被重复执行,随着游戏轮次增加
每次点击按钮显示图片,都会被重复执行
当点击一次按钮时,会输出三次点击效果,如果是第四轮游戏,就会同时输出四次点击效果,以此类推。。。
*/
// 假设 setupEventListener 是在这个函数内定义的
function outerFunction(callback) {
function setupModalListener() {
    const buttonGroup = document.getElementById('buttonGroup');
    if (buttonGroup) {
        buttonGroup.addEventListener('click', function(event) {
            if (event.target && event.target.classList.contains('modalButton')) {
                // 根据按钮的 data-function 属性确定要显示的图片
                const fieldName = event.target.getAttribute('data-function');
                const fakeEvent = { key: '1' };
                displayImage(fieldName, fakeEvent.key);
            }
        });
    } else {
    }
}
// displayImage 函数保持不变
setupModalListener();
}
//*********上面这段代码
// 执行事件监听器设置
setupEventListener();
        // ... 其他需要坐标的函数
    } else {
    }
                    } else {
    }
            // 确保在这一点之后使用 latitude 和 longitude
if (latitude !== undefined && longitude !== undefined) {
    // 使用 latitude 和 longitude 的代码
    // ...
}
        }else {
    // 清空modalContent的内容
    modalContent.innerHTML = '';
//
    }
            }
    }, false);
// 括号被移动到最后了
});
        }
        realSend.call(this, value); // 使用正确的上下文调用原始send方法
    } catch (error) {
        console.error("send方法替换中发生错误:", error);
        // 可以选择在出错时调用原始send方法或者处理错误
        realSend.call(this, value);
    }

// 重写open方法以捕获请求URL
XMLHttpRequest.prototype.realOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
    this._url = url; // 保存请求的URL
    this.realOpen(method, url, async, user, pass);
};
    if (XMLHttpRequest.prototype.send === XMLHttpRequest.prototype.realSend) {
      //  console.error('Tampermonkey script failed to override XMLHttpRequest.send.');
    } else {
    }
})();