您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Convert single column layout to multi-column layout only when printing. Press Ctrl+S to open settings.
当前为
- // ==UserScript==
- // @name Multi-Column Layout for printing (Print Only)
- // @namespace http://tampermonkey.net/
- // @license MIT
- // @version 2.5
- // @description Convert single column layout to multi-column layout only when printing. Press Ctrl+S to open settings.
- // @author KQ yang
- // @match *://*/*
- // @match file:///*
- // @match http://127.0.0.1:*/*
- // @match http://localhost:*/*
- // @grant GM_addStyle
- // @run-at document-start
- // @noframes
- // ==/UserScript==
- (function() {
- 'use strict';
- // Add colorful title and usage instructions right after initialization
- console.log('%c Multi-Column Layout for Printing v2.3 ',
- 'background: #4A90E2; color: white; font-size: 14px; font-weight: bold; padding: 8px; border-radius: 4px; text-shadow: 1px 1px 1px rgba(0,0,0,0.2);');
- console.log('%c 📖 Usage: Press Ctrl+S to open settings, customize your layout, then Ctrl+P to print! ',
- 'background: #2ECC71; color: white; font-size: 12px; padding: 6px; border-radius: 4px;');
- // Default configuration
- const DEFAULT_CONFIG = {
- columns: 1,
- columnGap: '30px',
- fontSize: '16px',
- paragraphSpacing: '1em',
- enablePageBreak: true,
- lineHeight: '1.5',
- };
- // Load config from localStorage or use defaults
- let CONFIG = loadConfig();
- function loadConfig() {
- const savedConfig = localStorage.getItem('printLayoutConfig');
- return savedConfig ? {...DEFAULT_CONFIG, ...JSON.parse(savedConfig)} : DEFAULT_CONFIG;
- }
- function saveConfig(config) {
- localStorage.setItem('printLayoutConfig', JSON.stringify(config));
- CONFIG = config;
- updateStyles();
- }
- let configModal = null; // 将configModal提升为全局变量
- // Create and inject the configuration UI
- function createConfigUI() {
- // 如果已经存在modal,先移除
- if (configModal) {
- configModal.remove();
- }
- configModal = document.createElement('div');
- configModal.id = 'print-layout-config-modal';
- configModal.setAttribute('style', `
- all: initial;
- position: fixed !important;
- top: 50% !important;
- left: 50% !important;
- transform: translate(-50%, -50%) !important;
- background: white !important;
- padding: 30px !important;
- border-radius: 12px !important;
- box-shadow: 0 8px 24px rgba(0,0,0,0.15) !important;
- z-index: 2147483647 !important;
- display: none !important;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif !important;
- min-width: 320px !important;
- max-width: 90vw !important;
- animation: modalFadeIn 0.3s ease-out !important;
- color: black !important;
- `);
- const styleElement = document.createElement('style');
- styleElement.textContent = `
- @keyframes modalFadeIn {
- from {
- opacity: 0;
- transform: translate(-50%, -48%);
- }
- to {
- opacity: 1;
- transform: translate(-50%, -50%);
- }
- }
- .settings-row {
- margin-bottom: 20px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .settings-row label {
- color: #333;
- font-size: 14px;
- margin-right: 15px;
- }
- .settings-row input[type="number"],
- .settings-row input[type="text"] {
- width: 100px;
- padding: 8px;
- border: 1px solid #ddd;
- border-radius: 6px;
- font-size: 14px;
- transition: border-color 0.2s;
- }
- .settings-row input:focus {
- outline: none;
- border-color: #4A90E2;
- box-shadow: 0 0 0 2px rgba(74,144,226,0.2);
- }
- .settings-row input[type="checkbox"] {
- width: 18px;
- height: 18px;
- cursor: pointer;
- }
- .modal-title {
- color: #333;
- margin: 0 0 25px 0;
- font-size: 18px;
- font-weight: 600;
- border-bottom: 2px solid #eee;
- padding-bottom: 15px;
- }
- .modal-footer {
- margin-top: 25px;
- padding-top: 20px;
- border-top: 2px solid #eee;
- text-align: right;
- }
- .save-button {
- background: #4A90E2;
- color: white;
- border: none;
- padding: 10px 20px;
- border-radius: 6px;
- font-size: 14px;
- cursor: pointer;
- transition: background-color 0.2s;
- }
- .save-button:hover {
- background: #357ABD;
- }
- .close-button {
- position: absolute;
- top: 15px;
- right: 15px;
- background: none;
- border: none;
- font-size: 20px;
- cursor: pointer;
- color: #666;
- padding: 5px;
- line-height: 1;
- }
- .close-button:hover {
- color: #333;
- }
- #print-layout-config-modal {
- visibility: visible !important;
- display: block !important;
- }
- `;
- document.head.appendChild(styleElement);
- configModal.innerHTML = ''; // 清空现有内容
- const modalContent = document.createElement('div');
- modalContent.style.cssText = `
- all: initial;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
- color: black !important;
- `;
- modalContent.innerHTML = `
- <h3 class="modal-title">Print Layout Settings</h3>
- <button class="close-button" title="Close">×</button>
- <div class="settings-row">
- <label>Columns (1-4):</label>
- <input type="number" id="columns" min="1" max="4" value="${CONFIG.columns}">
- </div>
- <div class="settings-row">
- <label>Column Gap:</label>
- <input type="text" id="columnGap" value="${CONFIG.columnGap}">
- </div>
- <div class="settings-row">
- <label>Font Size:</label>
- <input type="text" id="fontSize" value="${CONFIG.fontSize}">
- </div>
- <div class="settings-row">
- <label>Paragraph Spacing:</label>
- <input type="text" id="paragraphSpacing" value="${CONFIG.paragraphSpacing}">
- </div>
- <div class="settings-row">
- <label>Line Height:</label>
- <input type="text" id="lineHeight" value="${CONFIG.lineHeight}">
- </div>
- <div class="settings-row">
- <label>Enable Page Break:</label>
- <input type="checkbox" id="enablePageBreak" ${CONFIG.enablePageBreak ? 'checked' : ''}>
- </div>
- <div class="modal-footer">
- <button class="save-button">Save Changes</button>
- </div>
- `;
- configModal.appendChild(modalContent);
- document.documentElement.appendChild(configModal);
- // Save button handler
- const saveButton = configModal.querySelector('.save-button');
- if (saveButton) {
- saveButton.addEventListener('click', () => {
- const newConfig = {
- columns: parseInt(configModal.querySelector('#columns').value, 10),
- columnGap: configModal.querySelector('#columnGap').value,
- fontSize: configModal.querySelector('#fontSize').value,
- paragraphSpacing: configModal.querySelector('#paragraphSpacing').value,
- lineHeight: configModal.querySelector('#lineHeight').value,
- enablePageBreak: configModal.querySelector('#enablePageBreak').checked
- };
- saveConfig(newConfig);
- configModal.style.setProperty('display', 'none', 'important');
- });
- }
- // Close button handler
- const closeButton = configModal.querySelector('.close-button');
- if (closeButton) {
- closeButton.addEventListener('click', () => {
- configModal.style.setProperty('display', 'none', 'important');
- });
- }
- // Click outside to close
- configModal.addEventListener('click', (e) => {
- if (e.target === configModal) {
- configModal.style.setProperty('display', 'none', 'important');
- }
- });
- return configModal;
- }
- function showConfigModal() {
- console.log('Showing config modal'); // 调试日志
- if (!configModal) {
- configModal = createConfigUI();
- }
- configModal.style.setProperty('display', 'block', 'important');
- configModal.style.setProperty('visibility', 'visible', 'important');
- }
- function hideConfigModal() {
- if (configModal) {
- configModal.style.setProperty('display', 'none', 'important');
- }
- }
- function toggleConfigModal() {
- if (!configModal || configModal.style.display === 'none') {
- showConfigModal();
- } else {
- hideConfigModal();
- }
- }
- // Create and update styles based on current config
- function updateStyles() {
- const styleSheet = `
- @media print {
- html, body {
- margin: 0 !important;
- padding: 0 !important;
- min-height: 0 !important;
- height: auto !important;
- }
- .print-column-container {
- column-count: ${CONFIG.columns} !important;
- column-gap: ${CONFIG.columnGap} !important;
- column-rule: 1px solid #ddd !important;
- width: 100% !important;
- margin: 0 !important;
- padding: 0 !important;
- min-height: 0 !important;
- height: auto !important;
- overflow: visible !important;
- box-sizing: border-box !important;
- font-size: ${CONFIG.fontSize} !important;
- line-height: ${CONFIG.lineHeight} !important;
- ${CONFIG.enablePageBreak ? '' : 'page-break-inside: avoid !important;'}
- }
- .print-column-container > * {
- break-inside: avoid !important;
- margin-bottom: ${CONFIG.paragraphSpacing} !important;
- max-width: 100% !important;
- box-sizing: border-box !important;
- page-break-inside: avoid !important;
- }
- .print-column-container img {
- max-width: 100% !important;
- height: auto !important;
- page-break-inside: avoid !important;
- }
- }
- `;
- const existingStyle = document.getElementById('print-layout-style');
- if (existingStyle) {
- existingStyle.remove();
- }
- const style = document.createElement('style');
- style.id = 'print-layout-style';
- style.textContent = styleSheet;
- document.head.appendChild(style);
- }
- // Apply columns to main content
- function applyPrintColumns() {
- const mainContent = document.querySelector('.target-content') || document.body;
- mainContent.classList.add('print-column-container');
- const printStyle = document.createElement('style');
- printStyle.media = 'print';
- printStyle.textContent = `
- @page {
- margin: 1cm !important;
- padding: 0 !important;
- size: auto !important;
- }
- `;
- document.head.appendChild(printStyle);
- }
- // Initialize modal globally
- configModal = createConfigUI();
- // Handle Ctrl+S shortcut with improved event handling
- document.addEventListener('keydown', function(e) {
- if (e.ctrlKey && (e.key === 's' || e.key === 'S' || e.keyCode === 83)) {
- console.log('Ctrl+S detected'); // 调试日志
- e.stopPropagation();
- e.preventDefault();
- toggleConfigModal();
- return false;
- }
- }, true);
- // Initial style application
- updateStyles();
- // Handle DOMContentLoaded
- function onDOMContentLoaded() {
- applyPrintColumns();
- }
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', onDOMContentLoaded);
- } else {
- onDOMContentLoaded();
- }
- // Add a global function for testing
- window.togglePrintLayoutConfig = toggleConfigModal;
- })();