您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
入力されている全文をポップアップ表示し、ポップアップ内で編集可能。不要なスペースと重複ワードの検出・削除。全角スペースを半角に。文字数カウンターを追加。ブラウザタブタイトルにコードを追加。
// ==UserScript== // @name タイトルの改良 // @namespace http://tampermonkey.net/ // @version 1.31 // @description 入力されている全文をポップアップ表示し、ポップアップ内で編集可能。不要なスペースと重複ワードの検出・削除。全角スペースを半角に。文字数カウンターを追加。ブラウザタブタイトルにコードを追加。 // @license MIT // @match *://plus-nao.com/forests/*/mainedit/* // @match *://plus-nao.com/forests/*/registered_mainedit/* // @grant none // @run-at document-end // ==/UserScript== (function() { 'use strict'; document.title += "/" + window.location.href.split('/').pop(); const MAX_LENGTH = 255; let isEditingPopup = false; const style = document.createElement('style'); style.textContent = ` .cursor-warning { color: red; } `; document.head.appendChild(style); window.addEventListener('load', function() { const targetTd = document.querySelector('td[colspan="3"]:has(input[name="data[TbMainproduct][daihyo_syohin_name]"])'); if (targetTd) { const computedStyle = window.getComputedStyle(targetTd); const paddingTop = computedStyle.paddingTop; if (paddingTop === '7px') { targetTd.style.position = 'relative'; targetTd.style.paddingTop = '30px'; } } const inputFieldId = 'TbMainproductDaihyoSyohinName'; const inputField = document.getElementById(inputFieldId); if (!inputField) return; const wrapperDiv = document.createElement('div'); wrapperDiv.style.position = 'relative'; inputField.parentNode.insertBefore(wrapperDiv, inputField); wrapperDiv.appendChild(inputField); inputField.style.width = 'calc(100% - 60px)'; const popupStyle = ` position: absolute; background-color: white; border: 2px solid #ccc; border-radius: 5px; padding: 4px 10px; z-index: 1000; display: none; overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; width: calc(100% - 60px); `; const popup = document.createElement('div'); popup.className = 'title-popup'; popup.style.cssText = popupStyle; popup.contentEditable = true; wrapperDiv.appendChild(popup); function syncPopupToInput() { const updatedText = popup.textContent.replace(/\n/g, ' '); inputField.value = updatedText; updateButtonVisibility(); updateCursorPosition(true); } function updatePopup() { if (inputField === document.activeElement && inputField.value.trim() !== '') { popup.textContent = inputField.value; popup.style.display = 'block'; updatePopupText(); } else { popup.style.display = 'none'; } } function updatePopupText() { const text = inputField.value; popup.textContent = text; } const popupElement = document.querySelector('#popup'); const observer = new MutationObserver(function(mutationsList) { for (const mutation of mutationsList) { if (mutation.type === 'attributes' && mutation.attributeName === 'style') { if (popupElement.style.display === 'none') { popup.style.display = 'none'; } } } }); if (popupElement) { observer.observe(popupElement, { attributes: true }); } document.addEventListener('click', function(event) { if (popup.style.display === 'block' && !popup.contains(event.target) && !inputField.contains(event.target) && !event.target.closest('.suggest-popup')) { const selection = window.getSelection(); if (selection.rangeCount > 0) { const range = selection.getRangeAt(0); const startContainer = range.startContainer; const endContainer = range.endContainer; if (wrapperDiv.contains(startContainer) || wrapperDiv.contains(endContainer)) { return; } } popup.style.display = 'none'; inputField.blur(); updateButtonVisibility(); updateCursorPosition(false); } }); const textObserver = new MutationObserver(() => { const updatedText = popup.textContent.replace(/\n/g, ' '); inputField.value = updatedText; updateButtonVisibility(); updateCursorPosition(true); }); if (popup) { textObserver.observe(popup, { childList: true, subtree: true, characterData: true }); } popup.addEventListener('mouseup', () => { updateCursorPosition(true); }); popup.addEventListener('focus', function() { isEditingPopup = true; updateCursorPosition(true); }); popup.addEventListener('blur', function() { if (popup.textContent.length > MAX_LENGTH) { alert(`入力可能な文字数を超えています。256字以降は切り捨てられます。`); } const updatedText = popup.textContent.replace(/\n/g, ' '); popup.textContent = updatedText; inputField.value = updatedText; validatePopupInput(); isEditingPopup = false; updateCursorPosition(false); }); popup.addEventListener('keydown', function (event) { const selection = window.getSelection(); const range = selection.getRangeAt(0); const cursorOffset = range.startOffset; if (event.key === 'Enter') { const beforeCursor = popup.textContent.slice(0, cursorOffset); const afterCursor = popup.textContent.slice(cursorOffset); popup.textContent = beforeCursor + ' ' + afterCursor; const newRange = document.createRange(); const firstChild = popup.firstChild; if (firstChild && firstChild.nodeType === 3) { const newCursorPosition = beforeCursor.length + 1; newRange.setStart(firstChild, newCursorPosition); newRange.collapse(true); selection.removeAllRanges(); selection.addRange(newRange); setTimeout(() => { updateCursorPosition(document.activeElement === popup, newCursorPosition); }, 0); } inputField.value = popup.textContent; event.preventDefault(); } else { setTimeout(() => { updateCursorPosition(document.activeElement === popup); }, 0); } }); popup.addEventListener('paste', function (event) { event.preventDefault(); const clipboardData = event.clipboardData || window.clipboardData; const pasteText = clipboardData.getData('text/plain'); const selection = window.getSelection(); const range = selection.getRangeAt(0); const cursorOffset = range.startOffset; range.deleteContents(); const beforeCursor = popup.textContent.slice(0, cursorOffset); const afterCursor = popup.textContent.slice(cursorOffset); const updatedPasteText = pasteText.replace(/\n/g, ' '); popup.textContent = beforeCursor + updatedPasteText + afterCursor; const newCursorPosition = beforeCursor.length + updatedPasteText.length; const newRange = document.createRange(); newRange.setStart(popup.firstChild, newCursorPosition); newRange.collapse(true); selection.removeAllRanges(); selection.addRange(newRange); inputField.value = popup.textContent; updateButtonVisibility(); updateCursorPosition(true); }); popup.addEventListener('input', () => { const selection = window.getSelection(); const range = selection.getRangeAt(0); const startOffset = range.startOffset; const startNode = range.startContainer; const text = popup.textContent; const updatedText = text.replace(/\n/g, ' '); inputField.value = updatedText; updateButtonVisibility(); updateCursorPosition(true); const newRange = document.createRange(); newRange.setStart(startNode, Math.min(startOffset, text.length)); newRange.collapse(true); selection.removeAllRanges(); selection.addRange(newRange); }); let lastCursorPosition = null; const suggestPopupElements = document.querySelectorAll('.suggest-popup'); suggestPopupElements.forEach(suggestPopup => { suggestPopup.addEventListener('mousedown', (e) => { if (!isEditingPopup) return; e.preventDefault(); const selection = window.getSelection(); if (selection.rangeCount > 0) { const range = selection.getRangeAt(0); lastCursorPosition = { node: range.startContainer, offset: range.startOffset, }; } }); suggestPopup.addEventListener('click', (e) => { if (!isEditingPopup) return; if (e.target.classList.contains('add-word-button')) return; if (lastCursorPosition) { const selection = window.getSelection(); const newRange = document.createRange(); newRange.setStart(lastCursorPosition.node, lastCursorPosition.offset); newRange.collapse(true); selection.removeAllRanges(); selection.addRange(newRange); updateCursorPosition(true); } }); }); function updateInputField() { inputField.value = popup.textContent; updateButtonVisibility(); updateCursorPosition(true); } function updateInputFieldCursorFromPopup() { const selection = window.getSelection(); const range = selection.getRangeAt(0); const offset = range.startOffset; const text = popup.textContent; const cursorPos = getCharacterOffsetFromPopup(text, offset); inputField.setSelectionRange(cursorPos, cursorPos); inputField.focus(); updateCursorPosition(true); } function getCharacterOffsetFromPopup(text, offset) { return offset; } const spaceFixButton = createButton('スペース修正'); const removeDuplicatesButton = createButton('重複削除'); const cursorPosition = createCursorPosition(); wrapperDiv.appendChild(cursorPosition); addHighlightStyles(); if (isRegisteredEditPage()) { const buttonContainer = document.createElement('div'); buttonContainer.style.position = 'absolute'; buttonContainer.style.top = '-29px'; buttonContainer.style.right = '55px'; buttonContainer.style.display = 'flex'; buttonContainer.style.flexDirection = 'row'; buttonContainer.style.gap = '10px'; buttonContainer.style.zIndex = '1000'; inputField.parentNode.style.position = 'relative'; inputField.parentNode.appendChild(buttonContainer); setButtonStyles(removeDuplicatesButton, { backgroundColor: 'transparent', color: '#000000', border: '1px solid #ccc', padding: '0px 7px', marginLeft: '5px', marginTop: '4px', borderRadius: '5px', cursor: 'pointer', fontSize: '12px', visibility: 'hidden', transition: 'background-color 0.3s, transform 0.1s', }); setButtonStyles(spaceFixButton, { backgroundColor: 'transparent', color: '#000000', border: '1px solid #ccc', padding: '0px 7px', marginLeft: '5px', marginTop: '4px', borderRadius: '5px', cursor: 'pointer', fontSize: '12px', visibility: 'hidden', transition: 'background-color 0.3s, transform 0.1s', }); buttonContainer.appendChild(spaceFixButton); buttonContainer.appendChild(removeDuplicatesButton); updateButtonVisibility(); } else if (isMainEditPage()) { const buttonContainer = document.createElement('div'); buttonContainer.style.position = 'absolute'; buttonContainer.style.top = '-29px'; buttonContainer.style.right = '55px'; buttonContainer.style.display = 'flex'; buttonContainer.style.flexDirection = 'row'; buttonContainer.style.gap = '10px'; buttonContainer.style.zIndex = '1000'; inputField.parentNode.style.position = 'relative'; inputField.parentNode.appendChild(buttonContainer); setButtonStyles(removeDuplicatesButton, { backgroundColor: 'transparent', color: '#000000', border: '1px solid #ccc', padding: '0px 7px', marginLeft: '5px', marginTop: '4px', borderRadius: '5px', cursor: 'pointer', fontSize: '12px', visibility: 'hidden', transition: 'background-color 0.3s, transform 0.1s', }); setButtonStyles(spaceFixButton, { backgroundColor: 'transparent', color: '#000000', border: '1px solid #ccc', padding: '0px 7px', marginLeft: '5px', marginTop: '4px', borderRadius: '5px', cursor: 'pointer', fontSize: '12px', visibility: 'hidden', transition: 'background-color 0.3s, transform 0.1s', }); buttonContainer.appendChild(spaceFixButton); buttonContainer.appendChild(removeDuplicatesButton); updateButtonVisibility(); } inputField.addEventListener('blur', function() { updateCursorPosition(false); }); inputField.addEventListener('focus', function() { updatePopup(); updateCursorPosition(true); }); inputField.addEventListener('input', function() { updatePopup(); }); inputField.addEventListener('keyup', function() { updateCursorPosition(true); }); inputField.addEventListener('click', function() { updateCursorPosition(true); }); spaceFixButton.addEventListener('click', function(event) { event.preventDefault(); event.stopPropagation(); handleSpaceFixClick(inputField, spaceFixButton); addClickFeedback(spaceFixButton); }); removeDuplicatesButton.addEventListener('click', function(event) { event.preventDefault(); event.stopPropagation(); handleRemoveDuplicatesClick(inputField, removeDuplicatesButton); addClickFeedback(removeDuplicatesButton); }); removeDuplicatesButton.addEventListener('mouseover', function() { const duplicates = getDuplicateWords(inputField.value); if (duplicates.length > 0) { removeDuplicatesButton.title = `重複ワード: ${duplicates.join(', ')}`; } else { removeDuplicatesButton.title = ''; } }); function addClickFeedback(button) { button.style.transform = 'scale(0.9)'; setTimeout(() => { button.style.transform = 'scale(1)'; }, 100); } function attachContainerToElement(container, selector) { const targetButton = document.querySelector(selector); if (targetButton) { const wrapper = document.createElement('div'); wrapper.style.display = 'inline-flex'; wrapper.style.alignItems = 'flex-end'; targetButton.parentNode.insertBefore(wrapper, targetButton.nextSibling); wrapper.appendChild(targetButton); wrapper.appendChild(container); } } function createButton(textContent) { const btn = document.createElement('button'); btn.textContent = textContent; return btn; } function createCursorPosition() { const span = document.createElement('span'); span.style.marginLeft = '3px'; span.style.fontSize = '11px'; span.style.verticalAlign = 'middle'; return span; } function addHighlightStyles() { const style = document.createElement('style'); style.innerHTML = ` .highlight { border: 2px solid #ff0000; background-color: #fff5f5; } `; document.head.appendChild(style); } function isRegisteredEditPage() { return window.location.href.includes('/forests/TbMainproducts/registered_mainedit/') || window.location.href.includes('/forests/tb_mainproducts/registered_mainedit/'); } function isMainEditPage() { return window.location.href.includes('/forests/TbMainproducts/mainedit/') || window.location.href.includes('/forests/tb_mainproducts/mainedit/'); } function setButtonStyles(button, styles) { Object.assign(button.style, styles); button.addEventListener('mouseover', function() { button.style.backgroundColor = '#f0f0f0'; }); button.addEventListener('mouseout', function() { button.style.backgroundColor = 'transparent'; }); button.addEventListener('mousedown', function() { button.style.transform = 'scale(0.95)'; }); button.addEventListener('mouseup', function() { button.style.transform = 'scale(1)'; }); } function attachButtonToElement(button, selector, callback) { const targetButton = document.querySelector(selector); if (targetButton) { targetButton.parentNode.insertBefore(button, targetButton.nextSibling); callback(); } } function attachButtonToElementInTd(button, tagName, includeText1, includeText2, callback) { const parentTd = inputField.closest('td'); if (!parentTd) { return; } const targetElements = parentTd.getElementsByTagName(tagName); for (let i = 0; i < targetElements.length; i++) { if (targetElements[i].innerHTML.includes(includeText1) && targetElements[i].innerHTML.includes(includeText2)) { targetElements[i].appendChild(button); callback(); return; } } } function updateCursorPosition(focused, customPosition = null) { let position; let totalLength; if (focused && inputField === document.activeElement) { position = inputField.selectionStart; totalLength = inputField.value.length; } else if (focused && popup === document.activeElement) { const selection = window.getSelection(); position = customPosition !== null ? customPosition : selection.anchorOffset; totalLength = popup.textContent.length; } else { position = 0; totalLength = inputField.value.length; } cursorPosition.textContent = focused ? `${position}/${totalLength}` : `${totalLength}`; if (totalLength > MAX_LENGTH) { cursorPosition.classList.add('cursor-warning'); } else { cursorPosition.classList.remove('cursor-warning'); } } function validatePopupInput() { let currentText = popup.textContent; currentText = currentText.replace(/\n/g, ' '); if (currentText.length > MAX_LENGTH) { currentText = currentText.substring(0, MAX_LENGTH); popup.textContent = currentText; inputField.value = currentText; } } function updateButtonVisibility() { if (isEditingPopup) { return; } const value = inputField.value; const hasSpaceIssues = value.match(/\s{2,}| |^[\s ]+|[\s ]+$/); const hasDuplicates = hasDuplicateWords(value); if (hasSpaceIssues) { spaceFixButton.style.visibility = 'visible'; inputField.classList.add('highlight'); } else { spaceFixButton.style.visibility = 'hidden'; } if (hasDuplicates) { removeDuplicatesButton.style.visibility = 'visible'; inputField.classList.add('highlight'); } else { removeDuplicatesButton.style.visibility = 'hidden'; if (!hasSpaceIssues) { inputField.classList.remove('highlight'); } } updateCursorPosition(document.activeElement === inputField); } function handleSpaceFixClick(inputField, button) { const trimmedValue = inputField.value.trim(); let processedValue = trimmedValue.replace(/\s{2,}/g, ' '); processedValue = processedValue.replace(/ /g, ' '); inputField.value = processedValue; button.style.visibility = 'hidden'; updateButtonVisibility(); updatePopupContent(); updateCursorPosition(document.activeElement === inputField); } function updatePopupContent() { const text = inputField.value; popup.textContent = text; } function handleRemoveDuplicatesClick(inputField, button) { const value = inputField.value; const words = value.split(/\s+/); const uniqueWords = [...new Set(words)]; const processedValue = uniqueWords.join(' '); if (value !== processedValue) { inputField.value = processedValue; inputField.classList.add('highlight'); updatePopupContent(); } else { inputField.classList.remove('highlight'); } button.style.visibility = 'hidden'; updateButtonVisibility(); updateCursorPosition(document.activeElement === inputField); } function hasDuplicateWords(value) { const words = value.split(/\s+/).filter(word => word.trim() !== ''); const uniqueWords = new Set(words); return uniqueWords.size < words.length; } function getDuplicateWords(value) { const words = value.split(/\s+/).filter(word => word.trim() !== ''); const wordCount = {}; const duplicates = []; words.forEach(word => { wordCount[word] = (wordCount[word] || 0) + 1; }); for (const word in wordCount) { if (wordCount[word] > 1) { duplicates.push(word); } } return duplicates; } }); })();