// ==UserScript== // @name link工具 // @namespace http://tampermonkey.net/ // @version 0.9.0 // @description 点击复制,提取链接 // @author lwj // @match *://m.linkmcn.com/* // @match https://m.linkmcn.com/tableCard/redirect* // @match *://detail.tmall.com/item* // @match *://item.taobao.com/item* // @match *://chaoshi.detail.tmall.com/item* // @match *://traveldetail.fliggy.com/item* // @match *://detail.tmall.hk/hk/item* // @license MIT // @grant GM_setValue // @grant GM_getValue // @grant GM_setClipboard // @grant GM_xmlhttpRequest // @downloadURL none // ==/UserScript== (function () { // 版本号 var versionTitleTxt = 'Version 0.9.0'; // 检查当前页面 URL 是否匹配指定的网址 var isHomeURL = function () { var currentURL = window.location.href; return currentURL.indexOf("https://m.linkmcn.com/#/live/plan?select=") !== -1; }; // 从 localStorage 中获取上一次的 URL,如果没有则设置为空字符串 let lastCurrentURL = localStorage.getItem('lastCurrentURL') || ''; var isTableCardURL = function () { return window.location.href.indexOf("https://m.linkmcn.com/#/live/plan/tableCard/") !== -1; }; var isBatchPrintURL = function () { return window.location.href.indexOf("https://m.linkmcn.com/#/live/plan/batchPrint") !== -1; }; var isTmallItemURL = function () { var url = window.location.href; // 检查URL是否包含任何指定的域名或路径 return ( url.indexOf("https://detail.tmall.com/item") !== -1 || url.indexOf("https://detail.tmall.hk/hk/item") !== -1 || url.indexOf("https://item.taobao.com/item") !== -1 || url.indexOf("https://chaoshi.detail.tmall.com/item") !== -1 || url.indexOf("https://traveldetail.fliggy.com/item") !== -1 ); } var isRedirectUrl = function () { return window.location.href.indexOf("https://item.taobao.com/item.htm?id=682878335608&link_redirectId=") !== -1; } var notificationTimer; // 通知计时器 var isHiding = false; // 标志,表示是否正在隐藏通知 let countSort_notificationTimeout = null;// 排序提示定时器 let temp_itemId = ''; class ToggleButtonComponent { constructor(localStorageKey, buttonText, dropdownContainer, useSpecialSwitch = 0, defaultState = false) { this.localStorageKey = localStorageKey; this.switchState = localStorage.getItem(this.localStorageKey) === null ? defaultState : localStorage.getItem(this.localStorageKey) === 'true'; this.buttonText = buttonText; this.dropdownContainer = dropdownContainer; this.useSpecialSwitch = useSpecialSwitch === 1; this.createComponent(); } createComponent() { // 创建按钮容器 this.buttonContainer = document.createElement('div'); this.buttonContainer.classList.add('flex', 'items-center', 'dropdown-item'); this.buttonContainer.style.cssText = 'padding: 12px 16px; user-select: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center;'; if (this.buttonText === '纯净模式') { this.buttonContainer.style.paddingTop = '0px'; } // 创建按钮文本 this.buttonTextElement = document.createElement('span'); this.buttonTextElement.textContent = this.buttonText; this.buttonTextElement.classList.add('lh-22'); this.buttonContainer.appendChild(this.buttonTextElement); if (this.useSpecialSwitch) { // 创建特殊开关样式按钮 this.createSpecialSwitch(); } else { // 创建普通按钮 this.createStandardButton(); } // 将按钮容器添加到下拉容器中 this.dropdownContainer.appendChild(this.buttonContainer); // 创建对应的空的子页面并设置样式 this.secondaryContent = document.createElement('div'); this.secondaryContent.id = this.localStorageKey + '-secondary-content'; this.secondaryContent.style.cssText = 'margin: 0px 10px; display: none; padding: 10px 12px; background: #E9E9E9; border: 1px solid #D2D2D2; border-radius: 10px;'; // 将子页面添加到按钮容器的下方 this.dropdownContainer.appendChild(this.secondaryContent); } createStandardButton() { this.button = document.createElement('button'); this.button.id = 'main_standardFunShowButton'; this.button.style.cssText = 'background: none; border: none; font-size: 16px; cursor: pointer; transition: transform 0.3s; margin: 0px 6px'; this.button.appendChild(createSVGIcon()); this.buttonContainer.appendChild(this.button); // 绑定点击事件 this.button.addEventListener('click', () => this.handleStandardButtonClick()); // 给标题绑定模拟点击开关事件 this.buttonTextElement.addEventListener('click', () => this.titleToSwitchClick()); } handleStandardButtonClick() { // 切换二级页面显示状态 const secondaryContent = document.getElementById(this.localStorageKey + '-secondary-content'); if (secondaryContent) { secondaryContent.style.display = secondaryContent.style.display === 'block' ? 'none' : 'block'; } else { console.log(`${this.buttonText} 二级页面异常`); } // 旋转按钮图标 const icon = this.button.querySelector('svg'); const rotation = icon.style.transform === 'rotate(90deg)' ? 'rotate(0deg)' : 'rotate(90deg)'; icon.style.transform = rotation; } createSpecialSwitch() { this.button = document.createElement('button'); this.button.innerHTML = '
'; this.button.setAttribute('type', 'button'); this.button.setAttribute('role', 'switch'); this.button.setAttribute('aria-checked', this.switchState); // 设置开关状态 this.button.classList.add('ant-switch', 'css-9fw9up'); if (this.switchState) { this.button.classList.add('ant-switch-checked'); } this.buttonContainer.appendChild(this.button); this.buttonContainer.style.cursor = 'default'; // 添加点击事件监听 this.button.addEventListener('click', () => this.handleSwitchClick()); } handleSwitchClick() { // 切换开关状态 const newState = this.button.getAttribute('aria-checked') === 'true' ? 'false' : 'true'; this.button.setAttribute('aria-checked', newState); if (newState === 'true') { this.button.classList.add('ant-switch-checked'); showNotification(`${this.buttonText}:开启`); } else { this.button.classList.remove('ant-switch-checked'); showNotification(`${this.buttonText}:关闭`); } // 更新开关状态 updateSwitchState(this.localStorageKey, newState === 'true'); } titleToSwitchClick() { // 模拟点击开关按钮 this.button.click(); } remove_titleToSwitchClick() { // 移除模拟点击开关按钮 this.buttonTextElement.removeEventListener('click', () => this.titleToSwitchClick()); } // 获取开关状态 getSwitchState() { return this.button.getAttribute('aria-checked') === 'true'; } // 获取子页面元素 getSecondaryContent() { return this.secondaryContent; } } class SonToggleButtonComponent extends ToggleButtonComponent { constructor(localStorageKey, buttonText, dropdownContainer, descriptionText, useSpecialSwitch = false, defaultState = false) { super(localStorageKey, buttonText, dropdownContainer, useSpecialSwitch, defaultState); this.buttonText = buttonText; this.descriptionText = descriptionText; this.createAdditionalContent(); } // 创建附加内容容器 createAdditionalContent() { // 修改按钮文本样式并去除 class="lh-22" this.buttonTextElement.style.cssText = 'font-size: 14px; margin: 0;'; this.buttonTextElement.classList.remove('lh-22'); // 调整父类的内容容器样式 this.buttonContainer.style.cssText = 'display: flex; user-select: none; justify-content: space-between; align-items: center; padding: 0;'; // 新增的说明容器 this.descriptionContainer = document.createElement('div'); this.descriptionContainer.classList.add('description-content'); this.descriptionContainer.style.cssText = 'font-size: 12px; color: #9B9B9B; user-select: none; margin: 5px 0px; padding-bottom: 5px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #D2D2D2; white-space: pre-wrap;'; this.descriptionContainer.textContent = this.descriptionText; if (this.descriptionText === '') this.descriptionContainer.style.paddingBottom = '0px'; // 子设置容器 this.childSettingsContainer = document.createElement('div'); this.childSettingsContainer.classList.add('child-settings'); this.childSettingsContainer.style.cssText = 'display: block; justify-content: space-between; align-items: center;'; // 初始化子开关容器的样式 this.updateSwitchStyle(); // 将说明容器和子设置容器添加到下拉容器中 this.dropdownContainer.appendChild(this.buttonContainer); this.dropdownContainer.appendChild(this.descriptionContainer); this.dropdownContainer.appendChild(this.childSettingsContainer); } // 重写createSpecialSwitch以添加额外的类 createSpecialSwitch() { // 确保父类方法被正确调用 super.createSpecialSwitch(); // 确保 this.button 已初始化 if (!this.button) { console.error('this.button is not initialized'); return; } // 将函数定义为对象的方法 this.autoInput_handleSwitchClick = () => { if (!this.getSwitchState()) { itemSort_inputConter.showSwitchDiv(true); // 显示输入内容选择框 itemSort_countInputFun.showNumberControlDiv(false); // 隐藏数字控制区 itemSort_countInputFun.toggleDivButtonState(false); // 关闭数字控制按钮 } }; if (this.buttonText === '自动填充') { // console.log(this.buttonText); this.button.addEventListener('click', () => this.autoInput_handleSwitchClick()); } // 添加额外的类 this.button.classList.add('ant-switch-small'); } // 独立的方法用于更新开关样式 updateSwitchStyle() { if (!this.getSwitchState()) { initializeContainerStyle(this.childSettingsContainer, false); // 使用函数初始化 } } // 控制单独组件的开启关闭 showSwitchDiv(flag) { if (flag) { initializeContainerStyle(this.buttonContainer, true); initializeContainerStyle(this.descriptionContainer, true); } else { initializeContainerStyle(this.buttonContainer, false); initializeContainerStyle(this.descriptionContainer, false); } } createSelectBox(options = ['', '0', '1', '2', '3', '999'], savedKey = this.localStorageKey + '_savedValue', container = this.buttonContainer) { // 先移除button元素 if (this.button) { this.buttonContainer.removeChild(this.button); } // 创建下拉框 const selectBox = document.createElement('select'); selectBox.setAttribute('id', this.localStorageKey + '-select-box'); selectBox.style.cssText = ` font-size: 14px; margin: 0; width: 42px; height: 18px; border: 1px solid rgb(155, 155, 155); background-color: rgb(249,249,249); color: rgb(155, 155, 155); border-radius: 20px; padding: 0 2.5%; -webkit-appearance: none; -moz-appearance: none; appearance: none; position: relative; cursor: pointer; `; options.forEach(value => { const option = document.createElement('option'); option.value = value; option.style.cssText = ` text-align: center; padding: 0 5px; `; option.textContent = value === '' ? '空' : value; selectBox.appendChild(option); }); const savedValue = localStorage.getItem(savedKey) || options[1]; selectBox.value = savedValue; selectBox.addEventListener('change', () => { localStorage.setItem(savedKey, selectBox.value); updateSwitchState(this.localStorageKey, selectBox.value); // 悬浮时和激活时边框颜色变化 selectBox.style.borderColor = '#ff6200'; }); // 悬浮时和激活时边框颜色变化 selectBox.addEventListener('mouseover', function () { selectBox.style.borderColor = '#ff6200'; }); selectBox.addEventListener('mouseout', function () { if (!selectBox.matches(':focus')) { selectBox.style.borderColor = 'rgb(155, 155, 155)'; } }); selectBox.addEventListener('focus', function () { selectBox.style.borderColor = '#ff6200'; }); selectBox.addEventListener('blur', function () { selectBox.style.borderColor = 'rgb(155, 155, 155)'; }); container.appendChild(selectBox); } createDivButton(beforeText, afterText, onClickCallback = null, container = this.buttonContainer) { // 先移除button元素 if (this.button) { this.buttonContainer.removeChild(this.button); } this.beforeText = beforeText; this.afterText = afterText; this.onClickCallback = onClickCallback; // 功能开启按钮 this.divButton = document.createElement('div'); this.divButton.setAttribute('id', this.localStorageKey + '_divButton'); this.divButton.textContent = beforeText; this.divButton.style.cssText = ` font-size: 14px; margin: 0; width: 42px; height: 18px; border: 1px solid rgb(155, 155, 155); background-color: rgb(249,249,249); color: rgb(155, 155, 155); border-radius: 20px; padding: 0 2%; -webkit-appearance: none; -moz-appearance: none; appearance: none; position: relative; cursor: pointer; user-select: none; text-align: center; `; // 悬浮时和激活时边框颜色变化 this.divButton.addEventListener('mouseover', () => { if (this.divButton.textContent === beforeText) { this.divButton.style.borderColor = '#ff6200'; } else { this.divButton.style.borderColor = 'rgb(155, 155, 155)'; } }); this.divButton.addEventListener('mouseout', () => { if (this.divButton.textContent === beforeText) { this.divButton.style.borderColor = 'rgb(155, 155, 155)'; } else { this.divButton.style.borderColor = 'rgb(249, 249, 249)'; } }); // 按钮点击事件 this.divButton.addEventListener('click', () => { this.toggleDivButtonState(); }); container.appendChild(this.divButton); } // 控制单独组件的开启关闭 toggleDivButtonState(isActivated = null) { // 如果提供了isActivated参数,则根据参数设置状态,否则根据当前状态切换 const shouldActivate = isActivated !== null ? isActivated : (this.divButton.textContent === this.beforeText); if (shouldActivate) { this.divButton.textContent = this.afterText; this.divButton.style.color = '#fff'; this.divButton.style.backgroundColor = '#ff0000'; this.divButton.style.borderColor = '#fff'; showNotification(`${this.buttonText}:开启`); if (this.onClickCallback) { this.onClickCallback(true); } } else { this.divButton.textContent = this.beforeText; this.divButton.style.color = 'rgb(155, 155, 155)'; this.divButton.style.backgroundColor = 'rgb(249,249,249)'; this.divButton.style.borderColor = 'rgb(155, 155, 155)'; showNotification(`${this.buttonText}:关闭`); if (this.onClickCallback) { this.onClickCallback(false); } } } // 判断开关开启状态 getDivButtonState() { if (this.divButton.textContent === this.beforeText) { return false;// 开关开启状态 } else { return true;// 开关关闭状态 } } createNumberControDiv(defaultNumber = 0, single = false, countType = 'none', savedKey = this.localStorageKey + '_savedValue', container = this.buttonContainer) { if (single) { //先移除button元素 if (this.button) { this.buttonContainer.removeChild(this.button); } } // 数字文本及SVG控制区 this.numberControDiv = document.createElement('div'); this.numberControDiv.style.cssText = ` font-size: 14px; display: flex; align-items: center; min-width: 42px; height: 18px; width: auto; border: 1px solid rgb(155, 155, 155); background-color: rgb(249,249,249); color: rgb(155, 155, 155); border-radius: 20px; padding: 0 2.5%; -webkit-appearance: none; -moz-appearance: none; appearance: none; position: relative; cursor: default; `; // 数字文本 this.countText = document.createElement('span'); this.countText.textContent = defaultNumber; // 使用默认数字 this.countText.style.cssText = 'font-size: 14px; margin: 0 auto; cursor: pointer;'; this.numberControDiv.appendChild(this.countText); // 创建函数来设置悬停颜色 function addHoverEffect(svgElement) { svgElement.addEventListener('mouseover', function () { var path = svgElement.querySelector('path'); if (path) { path.setAttribute('data-original-fill', path.getAttribute('fill')); path.setAttribute('fill', '#ff6200'); } }); svgElement.addEventListener('mouseout', function () { var path = svgElement.querySelector('path'); if (path) { path.setAttribute('fill', path.getAttribute('data-original-fill')); } }); } // SVG控制区 var svgControlDiv = document.createElement('div'); svgControlDiv.style.cssText = 'display: flex; flex-direction: column; justify-content: space-between; cursor: pointer;'; // 上方SVG var svgUp = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgUp.setAttribute("width", "6"); svgUp.setAttribute("height", "6"); svgUp.setAttribute("viewBox", "0 0 1024 1024"); svgUp.innerHTML = ` 标签或其他容器标签
if (element.tagName === 'P') {
// 找到所有 标签
const spans = element.querySelectorAll('span');
spans.forEach(span => {
// 创建一个临时的文本节点,用于插入 标签的内容
const textNode = document.createTextNode(span.textContent);
// 用文本节点替换 标签
span.parentNode.replaceChild(textNode, span);
});
}
// 递归处理子节点
for (let i = 0; i < element.children.length; i++) {
removeStyles(element.children[i]);
}
}
}
// 根据优先级排序colorMap,长文本优先
function sortColorMap(colorMap) {
return colorMap.slice().sort((a, b) => b.regex.source.length - a.regex.source.length);
}
// 应用颜色到现有的 span 或创建新的 span
function applyColor(span, color) {
if (!span.getAttribute('data-mce-style')) {
span.style.color = color;
span.setAttribute('data-mce-style', `color: ${color};`);
}
}
// 添加新样式
// 此函数用于向iframe文档中的所有 元素添加新的样式。
// 参数:
// - iframeDocument: iframe的文档对象
// - colorMap: 包含正则表达式和对应颜色的映射对象
function addNewStyles(iframeDocument, colorMap) {
const ps = iframeDocument.querySelectorAll('p');
ps.forEach(p => {
const innerHTML = p.innerHTML;
let newInnerHTML = '';
// 先按照标签进行分割
const spanParts = innerHTML.split(/(]*>.*?<\/span>)/);
spanParts.forEach(spanPart => {
if (spanPart.match(/^]*>.*<\/span>$/)) {
// 如果是标签包裹的部分,直接添加到 newInnerHTML
newInnerHTML += spanPart;
} else {
// 处理不包含的部分
const parts = spanPart.split(/( 标签
const ps = iframeDocument.querySelectorAll('p');
// 遍历每一个 标签
ps.forEach(p => {
let innerHTML = p.innerHTML;
let newInnerHTML = innerHTML;
// 遍历 JSON 中的每个键值对
Object.keys(replacementMap).forEach(key => {
const value = replacementMap[key];
// 使用正则表达式替换所有匹配的文本
const regex = new RegExp(key, 'g'); // 'g' 标志用于全局替换
newInnerHTML = newInnerHTML.replace(regex, value);
});
// 将新的 HTML 内容赋给 标签
p.innerHTML = newInnerHTML;
});
}
const activateIframeAndModifyStyles = activateElementId => {
const activateElement = document.querySelector(`#${activateElementId} .link-node-hover-text-container`);
if (activateElement) {
activateElement.click();
activateElement.focus();
const iframe = document.querySelector(`#${activateElementId} .tox-edit-area iframe`);
if (iframe) {
const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
if (iframeDocument) {
// 清除原有的样式
if (sonMain_drawColor.getSwitchState()) {
removeStyles(iframeDocument.body);
}
if (sonMain_calculator.getSwitchState()) {
findAndCalculateExpressions(iframeDocument, calculate);
}
if (sonMain_smartReplace.getSwitchState()) {
replaceTextContent(iframeDocument, replacementMap);
}
if (sonMain_drawColor.getSwitchState()) {
// 第一行红色标记
if (activateElementId === 'livePrice') {
if (sonMain_smartReplace.getSwitchState()) {
autoWriteAvgPrice(iframeDocument);
}
modifyFirstPTagAndSpans(iframeDocument);
applyPrefixSuffixColor(iframeDocument);
}
// 规格首行非sku描述行蓝色
if (activateElementId === 'skuDesc') {
skuDescFirstLineBlue(iframeDocument);
}
// 获取对应的颜色映射
const colorMap = colorMaps[activateElementId];
const colorMap2 = colorMaps2[activateElementId];
const colorMap3 = colorMaps3[activateElementId];
if (colorMap) {
if (activateElementId === 'inventory') {
handleInventoryStyles(iframeDocument);
} else if (activateElementId === 'preSetInventory') {
handlePreSetInventoryStyles(iframeDocument);
}
else {
addNewStyles(iframeDocument, colorMap);
addNewStyles(iframeDocument, colorMap2);
addNewStyles(iframeDocument, colorMap3);
}
} else {
console.error('未找到对应的颜色映射。');
}
removeDataProcessed(iframeDocument);
isMarioShow.push(activateElementId);
}
} else {
console.error('无法访问iframe文档。');
}
} else {
console.error('未找到iframe元素。');
}
} else {
console.error('未找到激活元素。');
}
};
const removeDataProcessed = doc => {
const replaceElements = doc.querySelectorAll('[data-replace="true"]');
replaceElements.forEach(element => {
const parentElement = element.parentElement;
if (parentElement.tagName.toLowerCase() === 'p') {
// 检查 标签是否只有一个子元素,并且是当前的
const hasOnlySpanChild = parentElement.children.length === 1 && parentElement.children[0] === element;
// 获取父 元素的纯文本内容(不包括子元素)
const parentText = parentElement.textContent.trim();
if (hasOnlySpanChild && parentText === '无效内容') {
// 如果 标签没有其他文本内容,移除整个 标签
parentElement.remove();
} else {
// 否则,清空 的文本内容
element.textContent = '';
}
} else {
// 如果父元素不是 ,清空 的文本内容
element.textContent = '';
}
});
};
// 规格首行非sku描述行蓝色
const skuDescFirstLineBlue = doc => {
const firstPTag = doc.querySelector('#tinymce p');
if (firstPTag) {
if (!check_skuDescFirstLine.test(firstPTag.textContent)) {
applyColor(firstPTag, colorLibrary.blue);
}
const spanTags = firstPTag.querySelectorAll('span');
spanTags.forEach(spanTag => {
if (!check_skuDescFirstLine.test(firstPTag.textContent)) {
applyColor(spanTag, colorLibrary.blue);
}
});
}
};
// 到手价数字行红色
const modifyFirstPTagAndSpans = doc => {
const firstPTag = doc.querySelector('#tinymce p');
if (firstPTag) {
if (numericRegex.test(firstPTag.textContent)) {
applyColor(firstPTag, colorLibrary.red);
}
const spanTags = firstPTag.querySelectorAll('span');
spanTags.forEach(spanTag => {
if (numericRegex.test(spanTag.textContent)) {
applyColor(spanTag, colorLibrary.red);
}
});
}
};
// 预设库存样式修改
const handlePreSetInventoryStyles = doc => {
function check_content(content) {
if (!numericRegex.test(content)) {
if (content.includes('不可控')) {
return false;
} else {
return true;
}
} else {
return false;
}
}
const pTags = doc.querySelectorAll('#tinymce p');
pTags.forEach(pTag => {
if (check_content(pTag.textContent)) {
pTag.textContent = '拉满';
const spanTags = pTag.querySelectorAll('span');
spanTags.forEach(spanTag => {
if (check_content(spanTag.textContent)) {
spanTag.textContent = '拉满';
}
});
}
});
};
// 现货库存样式修改
const handleInventoryStyles = doc => {
let firstPTagFound = false;
const pTags = doc.querySelectorAll('#tinymce p');
pTags.forEach(pTag => {
// 获取 标签内的所有文本内容,并将连续的 转换为 标签内的所有文本内容,并按 标签用于包裹分隔后的段落
const newPTag = document.createElement('p');
newPTag.innerHTML = segment;
if (numericRegex.test(segmentText) || segmentText.includes('--')) {
applyColor(newPTag, colorMaps.inventory.default);
} else {
if (firstPTagFound) {
applyColor(newPTag, colorMaps.inventory.color2);
} else {
applyColor(newPTag, colorMaps.inventory.color1);
}
}
// 在原 标签位置插入新的 标签
pTag.parentNode.insertBefore(newPTag, pTag);
});
// 移除原始的 标签
pTag.parentNode.removeChild(pTag);
});
};
function autoWriteAvgPrice(iframeDocument) {
const ps = iframeDocument.querySelectorAll('p');
// 更新检测输入格式的正则表达式,支持小数
const pattern = /^\d+(\.\d+)?(\/\d+(\.\d+)?[^\d/\*]+)([/\*]\d+(\.\d+)?[^\d/\*]+)*$/;
ps.forEach(p => {
if (p.querySelector('span')) {
// 情况 1: p 标签内有 span 标签,需要处理 span 内的文本
processSpans(p, pattern);
} else {
// 情况 2: 只有 p 标签,没有嵌套的 span 标签
let newInnerHTML = '';
// 分割HTML内容
const parts = p.innerHTML.split(/(
| )/);
parts.forEach(part => {
if (part.match(/(
| )/)) {
// 如果是
或 ,直接添加到 newInnerHTML
newInnerHTML += part;
} else {
let styledPart = part;
const sortedColorMap = sortColorMap(colorMap);
sortedColorMap.forEach(map => {
if (map.regex.test(part)) {
const color = map.color;
// 仅对不在标签内的内容进行着色处理
const match = map.regex.exec(part);
if (match) {
const span = document.createElement('span');
span.innerHTML = match[0];
applyColor(span, color);
styledPart = part.replace(map.regex, span.outerHTML);
}
}
});
newInnerHTML += styledPart;
}
});
}
});
p.innerHTML = newInnerHTML;
});
}
function applyPrefixSuffixColor(iframeDocument) {
const ps = iframeDocument.querySelectorAll('p');
ps.forEach(p => {
const innerHTML = p.innerHTML;
let newInnerHTML = '';
const parts = innerHTML.split(/(
| )/);
parts.forEach(part => {
const testApply = part.indexOf('折扣');
if (testApply !== -1 || priceGameplayRegex.test(part.textContent)) {
newInnerHTML += part;
return; // 跳过折扣行
}
const colonIndex = part.indexOf(':');
if (colonIndex !== -1) {
const prefix = part.substring(0, colonIndex + 1); // 包含“:”
const suffix = part.substring(colonIndex + 1);
// 创建临时 div 用于获取后缀的纯文本
const tempDiv = document.createElement('div');
tempDiv.innerHTML = suffix;
const plainTextSuffix = tempDiv.textContent || tempDiv.innerText || "";
// 检查后缀并应用颜色
let styledSuffix = suffix;
const suffixSpan = document.createElement('span');
suffixSpan.innerHTML = suffix;
if (numericRegex.test(plainTextSuffix)) {
applyColor(suffixSpan, colorLibrary.red);
styledSuffix = suffixSpan.outerHTML;
} else {
applyColor(suffixSpan, colorLibrary.gray);
styledSuffix = suffixSpan.outerHTML;
}
// 创建前缀 span 并应用颜色
const prefixSpan = document.createElement('span');
prefixSpan.innerHTML = prefix;
if (numericRegex.test(plainTextSuffix)) {
applyColor(prefixSpan, colorLibrary.blue);
} else {
applyColor(prefixSpan, colorLibrary.gray);
}
newInnerHTML += prefixSpan.outerHTML + styledSuffix;
} else {
newInnerHTML += part;
}
});
p.innerHTML = newInnerHTML;
});
}
// 危险内容替换函数
function replaceTextContent(iframeDocument, replacementMap) {
// 获取所有的
let content = pTag.innerHTML.replace(/( )+/g, '无效内容
');
// 获取
标签分割成数组
const segments = content.split('
');
// 处理每个分割后的段落
segments.forEach((segment, index) => {
// 创建临时容器元素以便于操作 HTML 字符串
const tempContainer = document.createElement('div');
tempContainer.innerHTML = segment;
// 获取段落的纯文本内容
const segmentText = tempContainer.textContent;
if (!firstPTagFound && segmentText.includes('预售')) {
firstPTagFound = true;
}
// 创建新的
| )/);
parts.forEach(part => {
let styledPart = part;
// console.log("styledPart:" + styledPart);
// 检查part是否符合格式
if (pattern.test(part)) {
// 调用parseInput来解析part并生成新内容
const { price, num, units } = parseInput(part);
styledPart = generateOutput(price, num, units);
}
newInnerHTML += styledPart;
// console.log("newInnerHTML:" + newInnerHTML);
});
// 更新p元素的内容
p.innerHTML = newInnerHTML;
}
});
function processSpans(element, pattern) {
const spans = element.querySelectorAll('span');
spans.forEach(span => {
const textContent = span.textContent;
// 检查textContent是否符合格式
if (pattern.test(textContent)) {
// 调用parseInput来解析textContent并生成新内容
const { price, num, units } = parseInput(textContent);
const newContent = generateOutput(price, num, units);
// 更新span的内容
span.innerHTML = newContent;
}
});
}
}
// 定义parseInput函数,用于解析输入
function parseInput(input) {
const pattern = /^\d+(\.\d+)?(\/\d+(\.\d+)?[^\d/\*]+)([/\*]\d+(\.\d+)?[^\d/\*]+)*$/;
if (!pattern.test(input)) {
throw new Error("输入格式不正确");
}
const priceMatch = input.match(/^\d+(\.\d+)?/);
const price = priceMatch ? parseFloat(priceMatch[0]) : null;
let rex = [];
let num = [];
let units = [];
const matches = input.match(/([/\*])(\d+(\.\d+)?)([^\d/\*]+)/g);
if (matches) {
matches.forEach((match, index) => {
const [, symbol, number, , unit] = match.match(/([/\*])(\d+(\.\d+)?)([^\d/\*]+)/);
rex.push(symbol);
let quantity = parseFloat(number);
if (symbol === "*" && index > 0) {
quantity *= num[num.length - 1];
}
num.push(quantity);
units.push(unit.trim());
});
}
return { price, rex, num, units };
}
// 定义generateOutput函数,用于生成输出内容
function generateOutput(price, num, units) {
let output = `到手共${num[0]}${units[0]}
`;
for (let i = 0; i < num.length; i++) {
let avgPrice = (price / num[i]).toFixed(2).replace(/\.?0+$/, ""); // 计算结果并去掉末尾多余的零
output += `平均每${units[i]}${avgPrice}
`;
if (i < num.length - 1) {
output += `到手共${num[i + 1]}${units[i + 1]}
`;
}
}
// style="color: rgb(236, 40, 39);" data-mce-style="color: rgb(236, 40, 39);" 添加红色
// 去除末尾多余的
output = output.replace(/
$/, "");
return output;
}
/*
计算器功能区
*/
const calculate = [
{
regex: /折扣力度.*?(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/,
replaceFunc: (text, result) => {
// 替换文本中的折扣内容
let updatedText = text.replace(/(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/, `${result}`);
// 确保结果前有一个“约”字,并且前面有“:”或“:”
if (!updatedText.includes('约')) {
// 检查是否已有“:”或“:”,防止重复添加
if (!updatedText.includes(':') && !updatedText.includes(':')) {
updatedText = updatedText.replace(/(折扣力度.*?)(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/, `$1:约${result}`);
} else {
updatedText = updatedText.replace(/(折扣力度.*?)(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/, `$1约${result}`);
}
} else {
updatedText = updatedText.replace(/(:约|:约)?(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/, `:约${result}`);
}
// 确保结果后面有一个“折”字
if (!updatedText.endsWith('折')) {
updatedText += '折';
}
return updatedText;
},
decimalPlaces: 1,
multiplier: 10,
trimTrailingZeros: true
},
{
regex: /.*?(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))==/,
replaceFunc: (text, result) => text.replace(/(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))==/, `${result}`),
decimalPlaces: 2,
multiplier: 1,
trimTrailingZeros: true
},
];
// 计算表达式的函数
const calculateExpression = (expression, decimalPlaces = 2, multiplier = 1, trimTrailingZeros = false) => {
try {
let result = eval(expression); // 注意:eval() 存在安全性问题,确保传入的表达式是安全的。
result = result * multiplier; // 放大结果
let formattedResult = result.toFixed(decimalPlaces); // 保留指定的小数位数
// 根据参数决定是否去除末尾的零
if (trimTrailingZeros) {
formattedResult = parseFloat(formattedResult).toString();
}
return formattedResult;
} catch (e) {
console.error('表达式计算错误:', e);
return expression; // 如果计算错误,返回原表达式
}
};
const findAndCalculateExpressions = (iframeDocument, calculate) => {
const discountElements = iframeDocument.querySelectorAll('p, span');
discountElements.forEach(element => {
let text = element.textContent.replace(/。/g, '.'); // 替换所有中文小数点为英文小数点
text = text.replace(/(/g, '(').replace(/)/g, ')'); // 替换中文括号为英文括号
calculate.forEach(({ regex, replaceFunc, decimalPlaces, multiplier, trimTrailingZeros }) => {
const match = text.match(regex);
// console.log(match);
if (match) {
const expression = match[1];
// 检查是否为“折扣力度”的正则表达式
if (regex.source.includes('折扣力度')) {
if (/[+\-*/()]/.test(expression)) {
// 如果表达式包含运算符,进行计算
const result = calculateExpression(expression, decimalPlaces, multiplier, trimTrailingZeros);
text = replaceFunc(text, result);
} else {
// 如果表达式不包含运算符,直接使用替换函数处理
text = replaceFunc(text, expression);
}
} else {
// 其他情况照常处理
// 检查表达式是否包含运算符
if (/[+\-*/()]/.test(expression)) {
const result = calculateExpression(expression, decimalPlaces, multiplier, trimTrailingZeros);
text = replaceFunc(text, result);
}
}
element.textContent = text;
}
});
});
};
// 新增控制功能
// 支持单个元素内容的着色
// 封装函数返回包含SVG图标的div
function createMarioSVGIconWrapper(id, isClick = true, size = 14) {
// 创建一个 div 容器
var divWrapper = document.createElement('div');
divWrapper.className = 'svg-icon-wrapper'; // 添加一个类名,便于查找和样式控制
divWrapper.style.cssText = 'align-items: center; cursor: pointer; display: none;'; // 样式控制';
// 设置 div 的 id
if (id) {
divWrapper.id = id;
}
// 创建 SVG 图标
var svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svgIcon.setAttribute('class', 'icon custom-mario-svg'); // 添加自定义类名
svgIcon.setAttribute('viewBox', '0 0 1024 1024');
svgIcon.setAttribute('width', size);
svgIcon.setAttribute('height', size);
svgIcon.innerHTML = '