タイトル入力補助

本登録時にタイトルを送信し収集。収集されたデータからワード候補を表示。

// ==UserScript==
// @name         タイトル入力補助
// @namespace    http://tampermonkey.net/
// @version      1.10
// @description  本登録時にタイトルを送信し収集。収集されたデータからワード候補を表示。
// @license      MIT
// @match        *://plus-nao.com/forests/*/mainedit/*
// @match        *://plus-nao.com/forests/*/registered_mainedit/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==

(async function () {
    'use strict';

    const url = 'https://raw.githubusercontent.com/NEL227/my-data-repo/main/data/NGwords.txt';
    const dbName = 'ngWordsDB';
    const storeName = 'ngWordsStore';
    const keyName = 'ngWords';

    let ngWords = [];

    const db = await openDatabase();

    try {
        const cachedData = await getFromDB(db, storeName, keyName);
        const oneDayInMillis = 24 * 60 * 60 * 1000;
        const now = new Date();

        if (cachedData && now - new Date(cachedData.timestamp) <= oneDayInMillis) {
            ngWords = cachedData.words;
        }
    } catch (error) {}

    initMainScript(ngWords);

    try {
        const response = await fetch(url);
        if (response.ok) {
            const text = await response.text();
            const newWords = text.split('\n').map(word => word.trim()).filter(word => word);

            if (JSON.stringify(newWords) !== JSON.stringify(ngWords)) {
                ngWords = newWords;
                await saveToDB(db, storeName, { id: keyName, words: ngWords, timestamp: new Date() });
            }
        }
    } catch (error) {}

    function openDatabase() {
        return new Promise((resolve) => {
            const request = indexedDB.open(dbName, 1);
            request.onsuccess = () => resolve(request.result);
            request.onupgradeneeded = (event) => {
                const db = event.target.result;
                if (!db.objectStoreNames.contains(storeName)) {
                    db.createObjectStore(storeName, { keyPath: 'id' });
                }
            };
        });
    }

    function getFromDB(db, store, key) {
        return new Promise((resolve, reject) => {
            const transaction = db.transaction([store], 'readonly');
            const objectStore = transaction.objectStore(store);
            const request = objectStore.get(key);
            request.onsuccess = () => resolve(request.result);
            request.onerror = () => reject();
        });
    }

    function saveToDB(db, store, data) {
        return new Promise((resolve, reject) => {
            const transaction = db.transaction([store], 'readwrite');
            const objectStore = transaction.objectStore(store);
            const request = objectStore.put(data);
            request.onsuccess = () => resolve();
            request.onerror = () => reject();
        });
    }

    function initMainScript(ngWords) {
        (function() {
            'use strict';

            const jsonURL = 'https://raw.githubusercontent.com/NEL227/my-data-repo/main/data/sorted_data.json';

            GM_addStyle(`
#popup {
    position: fixed;
    top: 1%;
    left: 0.5%;
    width: 400px;
    height: 800px;
    max-width: 100%;
    max-height: 98%;
    background: white;
    border: 1px solid black;
    padding: 10px;
    padding-left: 15px;
    box-shadow: 0 0 10px rgba(0,0,0,0.5);
    z-index: 10000;
    overflow-y: auto;
    display: none;
    border-radius: 5px;
    box-sizing: border-box;
}
 
#popup-header {
    display: flex;
    justify-content: center;
    align-items: center;
    font-weight: bold;
    font-size: 16px;
    height: 20px;
    position: sticky;
    top: -11px;
    background-color: white;
    z-index: 10;
    padding: 10px;
    border-bottom: 1px solid #ddd;
}
 
#popup-content {
    height: auto;
    overflow-y: visible;
    box-sizing: border-box;
}
 
#popup-close {
    cursor: pointer;
    background: transparent;
    color: black;
    border: none;
    font-size: 24px;
    padding: 10px;
    position: absolute;
    top: -11px;
    left: 1px;
    line-height: 1;
    border-radius: 5px;
    position: sticky;
    z-index: 11;
}
 
#popup-content ul {
    padding: 0;
    list-style: none;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1px;
    margin: 0;
}
 
#popup-content ul li {
    padding: 3px;
    padding-right: 5px;
    font-size: 14px;
    border-bottom: 1px solid #ddd;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
 
.add-word-button {
    background-color: #ffffff;
    color: #4CAF50;
    border: 1px solid #4CAF50;
    padding: 3px;
    cursor: pointer;
    font-size: 12px;
    margin-left: 5px;
    border-radius: 6px;
    transition: background-color 0.2s ease, transform 0.2s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    position: relative;
}
 
.add-word-button::before {
    content: '📑';
    font-size: 14px;
    display: block;
    position: relative;
    top: -1px;
    left: 1px;
}
 
.add-word-button::after {
    content: '';
    position: absolute;
    top: -5px;
    left: -5px;
    width: 34px;
    height: 34px;
    z-index: 0;
}
 
.add-word-button:hover {
    background-color: #4CAF50;
    color: #ffffff;
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
 
.add-word-button:active {
    background-color: #388E3C;
    transform: translateY(0);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
 
#show-subwords-button {
    background-color: #4CAF50;
    color: #fff;
    border: none;
    padding: 3px;
    border-radius: 5px;
    cursor: pointer;
    font-size: 12px;
    margin-top: 5px;
    display: block;
    width: 100px;
    text-align: center;
    transition: background-color 0.2s ease, transform 0.2s ease;
}
 
#show-subwords-button:hover:not(.disabled) {
    background-color: #388E3C;
}
 
#show-subwords-button:active:not(.disabled) {
    transform: translateY(2px);
}
 
#show-subwords-button.disabled {
    background-color: #ccc;
    cursor: default;
}
 
#show-subwords-button.active {
    background-color: #4CAF50;
    color: #ffffff;
    cursor: default;
}
 
#settings-button {
    background-color: #ffffff;
    color: #4CAF50;
    border: 1px solid #4CAF50;
    padding: 3px;
    cursor: pointer;
    font-size: 12px;
    border-radius: 6px;
    transition: background-color 0.2s ease, transform 0.2s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    margin-left: 5px;
    margin-top: 5.5px;
}
#settings-button::before {
    content: '⚙️';
    font-size: 14px;
    display: block;
    position: relative;
    top: -0.5px;
 
}
 
#settings-button:hover {
    background-color: #4CAF50;
    color: #ffffff;
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
 
#settings-button:active {
    background-color: #388E3C;
    transform: translateY(0);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
 
#settings-popup {
    position: fixed;
    top: 20%;
    left: 50%;
    transform: translateX(-50%);
    width: 300px;
    background: white;
    border: 1px solid black;
    padding: 10px;
    padding-left: 30px;
    box-shadow: 0 0 10px rgba(0,0,0,0.5);
    z-index: 10001;
    display: none;
    border-radius: 5px;
    box-sizing: border-box;
}
 
#settings-popup label {
    display: block;
    margin-bottom: 5px;
}
 
#settings-popup input,
#settings-popup button {
    box-sizing: border-box;
    width: calc(100% - 20px);
    padding: 5px;
    margin-bottom: 10px;
    display: block;
}
 
#settings-popup button {
    background-color: #4CAF50;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 12px;
    transition: background-color 0.2s ease, transform 0.2s ease;
    display: block;
}
 
#settings-popup button:hover {
    background-color: #388E3C;
}
 
#settings-popup button:active {
    transform: translateY(2px);
}
 
td[colspan="3"]:has(input[name="data[TbMainproduct][daihyo_syohin_name]"]) {
    position: relative;
    padding-top: 30px;
}
 
.button-container {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-top: 5px;
    position: absolute;
    left: 0;
    bottom: 0;
    transform: scale(0.9);
    z-index: 999;
}
 
#show-subwords-button.disabled.active {
    background-color: #388E3C;
}
    `);

            const popup = document.createElement('div');
            popup.id = 'popup';
            popup.className = 'suggest-popup';
            popup.innerHTML = `
    <button id="popup-close">×</button>
    <div id="popup-header"></div>
    <div id="popup-content"><ul></ul></div>
`;
            document.body.appendChild(popup);

            const settingsButton = document.createElement('button');
            settingsButton.id = 'settings-button';
            settingsButton.title = '設定';
            settingsButton.className = 'add-word-button';

            const settingsPopup = document.createElement('div');
            settingsPopup.id = 'settings-popup';
            settingsPopup.innerHTML = `
    <label for="popup-width">横幅 (px):</label>
    <input type="number" id="popup-width" value="400" step="10" />
    <label for="popup-height">高さ (px):</label>
    <input type="number" id="popup-height" value="800" step="10" />
    <button id="apply-settings">適用</button>
`;
            document.body.appendChild(settingsPopup);

            function fetchJSON(callback) {
                const cacheLifetime = 24 * 60 * 60 * 1000;

                getFromIndexedDB()
                    .then(cachedData => {
                    const now = new Date().getTime();

                    if (cachedData && (now - cachedData.timestamp < cacheLifetime)) {
                        callback(cachedData.data);
                    } else {
                        fetch(jsonURL, {
                            method: 'GET',
                            cache: 'no-cache'
                        })
                            .then(response => response.json())
                            .then(data => {
                            saveToIndexedDB(data)
                                .catch(error => console.error('データの保存中にエラーが発生しました:', error));

                            callback(data);
                        })
                            .catch(error => console.error('JSONデータの取得中にエラーが発生しました:', error));
                    }
                })
                    .catch(error => console.error('IndexedDBからのデータ取得中にエラーが発生しました:', error));
            }

            function handleData(data) {
                const inputField = document.querySelector('input[name="data[TbMainproduct][daihyo_syohin_name]"]');
                const inputField2A = document.querySelector('input[name="data[TbMainproduct][daihyo_syohin_name]"]');
                const inputField2B = document.querySelector('[contenteditable="true"]');
                let activeInputField2 = inputField2A || inputField2B;
                const button = document.getElementById('show-subwords-button');

                const setActiveInputField2 = (field) => {
                    activeInputField2 = field;
                };

                [inputField2A, inputField2B].forEach(field => {
                    if (field) {
                        field.addEventListener('focus', () => setActiveInputField2(field));
                    }
                });

                if (inputField) {
                    let inputValue = activeInputField2.textContent?.trim() || activeInputField2.value.trim();
                    let words = inputValue.split(/\s+/);
                    let mainWord = '';

                    if (words.length > 0) {
                        mainWord = words[0];

                        if (mainWord.endsWith('用') && words.length > 1) {
                            let secondWord = words[1];

                            if (!secondWord.endsWith('用')) {
                                mainWord = mainWord + secondWord.replace(/\s+/g, '');
                            }
                        }
                    }

                    if (data[mainWord]) {
                        const popupHeader = document.getElementById('popup-header');
                        if (popupHeader) {
                            popupHeader.textContent = `「${mainWord}」`;
                        }

                        const popupContent = document.getElementById('popup-content').querySelector('ul');

                        const updateSubwords = (currentInputValue) => {
                            const inputWords = currentInputValue.split(/\s+/);

                            const subwords = Object.entries(data[mainWord])
                            .filter(([subword]) => !ngWords.includes(subword))
                            .sort(([, aCount], [, bCount]) => bCount - aCount)
                            .map(([subword]) => {
                                const existsInInput = inputWords.includes(subword);
                                return `
                            <li style="color: ${existsInInput ? 'green' : 'black'};">
                                ${subword}
                                <button class="add-word-button" data-word="${subword}"></button>
                            </li>
                        `;
                            })
                            .join('');

                            popupContent.innerHTML = subwords;

                            document.querySelectorAll('.add-word-button').forEach(button => {
                                button.addEventListener('click', (event) => {
                                    const word = event.target.getAttribute('data-word');

                                    const text = activeInputField2.textContent || activeInputField2.value || '';
                                    const selection = window.getSelection();
                                    const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;

                                    let start = 0, end = 0;
                                    if (range && activeInputField2.isContentEditable) {
                                        start = range.startOffset;
                                        end = range.endOffset;
                                    } else if (activeInputField2.selectionStart !== undefined) {
                                        start = activeInputField2.selectionStart;
                                        end = activeInputField2.selectionEnd;
                                    }

                                    const before = text.slice(0, start) || '';
                                    const after = text.slice(end) || '';

                                    const needsSpaceBefore = (before && before.length > 0 && before[before.length - 1] !== ' ') || false;
                                    const needsSpaceAfter = (after && after.length > 0 && after[0] !== ' ') || false;

                                    const newValue = before + (needsSpaceBefore ? ' ' : '') + word + (needsSpaceAfter ? ' ' : '') + after;

                                    if (activeInputField2.isContentEditable) {
                                        activeInputField2.textContent = newValue;

                                        const newRange = document.createRange();
                                        newRange.setStart(activeInputField2.firstChild, start + word.length + (needsSpaceBefore ? 1 : 0));
                                        newRange.setEnd(activeInputField2.firstChild, start + word.length + (needsSpaceBefore ? 1 : 0));
                                        selection.removeAllRanges();
                                        selection.addRange(newRange);
                                    } else {
                                        activeInputField2.value = newValue;
                                        activeInputField2.setSelectionRange(start + word.length + (needsSpaceBefore ? 1 : 0), start + word.length + (needsSpaceBefore ? 1 : 0));
                                    }

                                    activeInputField2.focus();
                                    updateSubwords(activeInputField2.textContent?.trim() || activeInputField2.value.trim());
                                });
                            });
                        };

                        updateSubwords(inputValue);

                        activeInputField2.addEventListener('input', () => {
                            updateSubwords(activeInputField2.textContent?.trim() || activeInputField2.value.trim());
                        });

                        const popup = document.getElementById('popup');
                        if (popup) {
                            popup.style.display = 'block';
                            if (button) {
                                button.textContent = '表示中';
                                button.classList.add('disabled', 'active');
                                button.disabled = true;
                            }
                        }
                    } else {
                        if (button) {
                            button.textContent = '登録なし';
                            button.classList.add('disabled');
                            button.classList.remove('active');
                            button.disabled = true;
                        }
                    }
                }
            }

            function initDB() {
                return new Promise((resolve, reject) => {
                    const request = indexedDB.open('jsonCacheDB', 1);

                    request.onupgradeneeded = (event) => {
                        const db = event.target.result;
                        if (!db.objectStoreNames.contains('jsonData')) {
                            db.createObjectStore('jsonData', { keyPath: 'id' });
                        }
                    };

                    request.onsuccess = (event) => {
                        resolve(event.target.result);
                    };

                    request.onerror = (event) => {
                        reject('IndexedDBの初期化に失敗しました');
                    };
                });
            }

            function saveToIndexedDB(data) {
                return initDB().then(db => {
                    return new Promise((resolve, reject) => {
                        const transaction = db.transaction(['jsonData'], 'readwrite');
                        const store = transaction.objectStore('jsonData');
                        const cacheData = {
                            id: 'jsonData',
                            timestamp: new Date().getTime(),
                            data: data
                        };
                        store.put(cacheData);

                        transaction.oncomplete = () => resolve();
                        transaction.onerror = () => reject('データの保存に失敗しました');
                    });
                });
            }

            function getFromIndexedDB() {
                return initDB().then(db => {
                    return new Promise((resolve, reject) => {
                        const transaction = db.transaction(['jsonData'], 'readonly');
                        const store = transaction.objectStore('jsonData');
                        const request = store.get('jsonData');

                        request.onsuccess = (event) => {
                            resolve(event.target.result);
                        };

                        request.onerror = () => reject('データの取得に失敗しました');
                    });
                });
            }

            function adjustButtonContainerStyle() {
                const url = window.location.href;
                const buttonContainer = document.querySelector('.button-container');

                if (buttonContainer) {
                    if (url.includes('registered_mainedit')) {
                        buttonContainer.style.bottom = '31.5px';
                        buttonContainer.style.left = `1px`;
                    } else {
                        buttonContainer.style.bottom = '51px';
                        buttonContainer.style.left = `1px`;
                    }
                }
            }

            function addShowSubwordsButton() {
                const tdElement = document.querySelector('td[colspan="3"][scope="row"]');
                const inputField = document.querySelector('input[name="data[TbMainproduct][daihyo_syohin_name]"]');

                if (tdElement && inputField) {
                    const buttonContainer = document.createElement('div');
                    buttonContainer.className = 'button-container';

                    const showSubwordsButton = document.createElement('button');
                    showSubwordsButton.id = 'show-subwords-button';
                    showSubwordsButton.textContent = 'ワード候補';

                    const settingsButton = document.createElement('button');
                    settingsButton.id = 'settings-button';
                    settingsButton.title = '設定';
                    settingsButton.className = 'settings-button';

                    buttonContainer.appendChild(showSubwordsButton);
                    buttonContainer.appendChild(settingsButton);

                    tdElement.appendChild(buttonContainer);

                    adjustButtonContainerStyle();

                    showSubwordsButton.addEventListener('click', (event) => {
                        if (event.isTrusted) {
                            if (!showSubwordsButton.classList.contains('disabled')) {
                                event.preventDefault();
                                event.stopPropagation();
                                fetchJSON(data => handleData(data));
                            }
                        }
                    });

                    settingsButton.addEventListener('click', (event) => {
                        event.preventDefault();
                        event.stopPropagation();
                        toggleSettingsPopup();
                    });
                }
            }

            function toggleSettingsPopup() {
                const settingsPopup = document.getElementById('settings-popup');
                if (settingsPopup) {
                    settingsPopup.style.display = settingsPopup.style.display === 'block' ? 'none' : 'block';
                }
            }

            function closePopup() {
                const popup = document.getElementById('popup');
                const showSubwordsButton = document.getElementById('show-subwords-button');
                if (popup) {
                    popup.style.display = 'none';
                    if (showSubwordsButton) {
                        showSubwordsButton.textContent = 'ワード候補';
                        showSubwordsButton.classList.remove('disabled', 'active');
                        showSubwordsButton.disabled = false;
                    }
                }
            }

            function applySettings() {
                const width = document.getElementById('popup-width').value || 400;
                const height = document.getElementById('popup-height').value || 800;

                const popup = document.getElementById('popup');
                if (popup) {
                    popup.style.width = `${width}px`;
                    popup.style.height = `${height}px`;
                }

                localStorage.setItem('popupWidth', width);
                localStorage.setItem('popupHeight', height);
            }

            function closeSettingsOnClickOutside(event) {
                const settings = document.getElementById('settings-popup');
                const settingsButton = document.getElementById('settings-button');
                if (settings && !settings.contains(event.target) && event.target !== settingsButton) {
                    settings.style.display = 'none';
                }
            }

            document.addEventListener('keydown', function(event) {
                if (event.key === 'Escape') {
                    closePopup();
                }
            });

            document.addEventListener('click', function(event) {
                if (event.target.id === 'popup-close') {
                    closePopup();
                } else if (event.target.id === 'apply-settings') {
                    applySettings();
                }
            });

            settingsButton.addEventListener('click', (event) => {
                event.preventDefault();
                event.stopPropagation();
                toggleSettingsPopup();
            });

            document.addEventListener('click', closeSettingsOnClickOutside);

            const inputField = document.querySelector('input[name="data[TbMainproduct][daihyo_syohin_name]"]');
            if (inputField) {
                inputField.addEventListener('input', () => {
                    const button = document.getElementById('show-subwords-button');
                    const popup = document.getElementById('popup');

                    if (button && button.textContent === '登録なし') {
                        button.textContent = 'ワード候補';
                        button.classList.remove('disabled');
                        button.disabled = false;
                    }

                    if (popup && popup.style.display === 'block') {
                        button.textContent = '表示中(更新)';
                        button.classList.remove('disabled');
                        button.classList.add('active');
                        button.disabled = false;
                    }
                });
            }

            const observer = new MutationObserver((mutationsList, observer) => {
                mutationsList.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE && node.matches('.title-popup[contenteditable="true"]')) {

                            const checkButtonExistence = () => {
                                const button = document.getElementById('show-subwords-button');
                                if (button) {
                                    const popup = document.getElementById('popup');

                                    if (button && button.textContent === '登録なし') {
                                        button.textContent = 'ワード候補';
                                        button.classList.remove('disabled');
                                        button.disabled = false;
                                    }

                                    if (popup && popup.style.display === 'block') {
                                        button.textContent = '表示中(更新)';
                                        button.classList.remove('disabled');
                                        button.classList.add('active');
                                        button.disabled = false;
                                    }

                                    node.addEventListener('input', () => {
                                        if (button && button.textContent === '登録なし') {
                                            button.textContent = 'ワード候補';
                                            button.classList.remove('disabled');
                                            button.disabled = false;
                                        }

                                        if (popup && popup.style.display === 'block') {
                                            button.textContent = '表示中(更新)';
                                            button.classList.remove('disabled');
                                            button.classList.add('active');
                                            button.disabled = false;
                                        }
                                    });

                                    observer.disconnect();
                                } else {
                                    setTimeout(checkButtonExistence, 100);
                                }
                            };

                            checkButtonExistence();
                        }
                    });
                });
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true
            });

            window.addEventListener('load', () => {
                addShowSubwordsButton();

                const savedWidth = localStorage.getItem('popupWidth');
                const savedHeight = localStorage.getItem('popupHeight');

                if (savedWidth && savedHeight) {
                    const popup = document.getElementById('popup');
                    if (popup) {
                        popup.style.width = `${savedWidth}px`;
                        popup.style.height = `${savedHeight}px`;
                        document.getElementById('popup-width').value = savedWidth;
                        document.getElementById('popup-height').value = savedHeight;
                    }
                }

                fetchJSON(data => {
                });
            });

            //送信機能
            const API_URL = 'https://my-data-repo.vercel.app/api/github-proxy';

            const INPUT_SELECTOR = '#TbMainproductDaihyoSyohinName';
            const BUTTON_SELECTOR = '#saveAndSkuStock';

            function getFileShaAndContent(callback) {
                GM_xmlhttpRequest({
                    method: "GET",
                    url: `${API_URL}`,
                    onload: function(response) {
                        if (response.status === 200) {
                            const data = JSON.parse(response.responseText);
                            const sha = data.sha;
                            const existingContent = data.content;
                            callback(sha, existingContent);
                        } else {
                            console.error("ファイルの取得に失敗しました:", response.responseText);
                            callback(null, null);
                        }
                    },
                    onerror: function(error) {
                        console.error("エラーが発生しました:", error);
                        callback(null, null);
                    }
                });
            }

            function uploadData(retryCount = 0) {
                const inputElement = document.querySelector(INPUT_SELECTOR);
                if (inputElement) {
                    const newData = inputElement.value;

                    getFileShaAndContent(function(sha, existingContent) {
                        if (sha !== null) {
                            const updatedContent = existingContent + "\n" + newData;

                            GM_xmlhttpRequest({
                                method: "PUT",
                                url: API_URL,
                                headers: {
                                    "Content-Type": "application/json",
                                },
                                data: JSON.stringify({
                                    sha: sha,
                                    newData: updatedContent
                                }),
                                onload: function(response) {
                                    if (response.status === 200) {
                                        console.log("データ送信成功");
                                    } else if (response.status === 422 && retryCount < 3) {
                                        console.warn("競合確認...リトライ中");
                                        setTimeout(() => uploadData(retryCount + 1), 1000);
                                    } else {
                                        console.error("データ送信失敗:", response.responseText);
                                    }
                                },
                                onerror: function(error) {
                                    console.error("Error:", error);
                                    if (retryCount < 3) {
                                        setTimeout(() => uploadData(retryCount + 1), 1000);
                                    }
                                }
                            });
                        }
                    });
                }
            }

            function setupButtonListener() {
                const buttonElement = document.querySelector(BUTTON_SELECTOR);
                if (buttonElement) {
                    buttonElement.addEventListener('click', uploadData);
                }
            }

            setupButtonListener();

        })();
    }
})();