Multi-Column Layout for printing (Print Only)

Convert single column layout to multi-column layout only when printing. Double-press Ctrl key to open settings.

当前为 2024-11-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Multi-Column Layout for printing (Print Only)
  3. // @namespace http://tampermonkey.net/
  4. // @license MIT
  5. // @version 2.1
  6. // @description Convert single column layout to multi-column layout only when printing. Double-press Ctrl key to open settings.
  7. // @author KQ yang
  8. // @match *://*
  9. // @match file:///*
  10. // @match http://127.0.0.1:*/*
  11. // @match http://localhost:*/*
  12. // @grant GM_addStyle
  13. // @run-at document-end
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. // Default configuration
  20. const DEFAULT_CONFIG = {
  21. columns: 2,
  22. columnGap: '30px',
  23. fontSize: '16px',
  24. paragraphSpacing: '1em',
  25. enablePageBreak: true,
  26. lineHeight: '1.5',
  27. };
  28.  
  29. // Load config from localStorage or use defaults
  30. let CONFIG = loadConfig();
  31.  
  32. function loadConfig() {
  33. const savedConfig = localStorage.getItem('printLayoutConfig');
  34. return savedConfig ? {...DEFAULT_CONFIG, ...JSON.parse(savedConfig)} : DEFAULT_CONFIG;
  35. }
  36.  
  37. function saveConfig(config) {
  38. localStorage.setItem('printLayoutConfig', JSON.stringify(config));
  39. CONFIG = config;
  40. updateStyles();
  41. }
  42.  
  43. // Create and inject the configuration UI
  44. function createConfigUI() {
  45. const modal = document.createElement('div');
  46. modal.style.cssText = `
  47. position: fixed;
  48. top: 50%;
  49. left: 50%;
  50. transform: translate(-50%, -50%);
  51. background: white;
  52. padding: 20px;
  53. border-radius: 8px;
  54. box-shadow: 0 0 10px rgba(0,0,0,0.3);
  55. z-index: 9999;
  56. display: none;
  57. `;
  58.  
  59. modal.innerHTML = `
  60. <h3 style="margin-top: 0;">Print Layout Settings</h3>
  61. <div style="margin-bottom: 10px;">
  62. <label>Columns (1-4): </label>
  63. <input type="number" id="columns" min="1" max="4" value="${CONFIG.columns}">
  64. </div>
  65. <div style="margin-bottom: 10px;">
  66. <label>Column Gap: </label>
  67. <input type="text" id="columnGap" value="${CONFIG.columnGap}">
  68. </div>
  69. <div style="margin-bottom: 10px;">
  70. <label>Font Size: </label>
  71. <input type="text" id="fontSize" value="${CONFIG.fontSize}">
  72. </div>
  73. <div style="margin-bottom: 10px;">
  74. <label>Paragraph Spacing: </label>
  75. <input type="text" id="paragraphSpacing" value="${CONFIG.paragraphSpacing}">
  76. </div>
  77. <div style="margin-bottom: 10px;">
  78. <label>Line Height: </label>
  79. <input type="text" id="lineHeight" value="${CONFIG.lineHeight}">
  80. </div>
  81. <div style="margin-bottom: 10px;">
  82. <label>Enable Page Break: </label>
  83. <input type="checkbox" id="enablePageBreak" ${CONFIG.enablePageBreak ? 'checked' : ''}>
  84. </div>
  85. <div style="text-align: right; margin-top: 20px;">
  86. <button id="saveConfig" style="padding: 5px 10px;">Save</button>
  87. </div>
  88. `;
  89.  
  90. document.body.appendChild(modal);
  91.  
  92. // Save button handler
  93. document.getElementById('saveConfig').addEventListener('click', () => {
  94. const newConfig = {
  95. columns: parseInt(document.getElementById('columns').value, 10),
  96. columnGap: document.getElementById('columnGap').value,
  97. fontSize: document.getElementById('fontSize').value,
  98. paragraphSpacing: document.getElementById('paragraphSpacing').value,
  99. lineHeight: document.getElementById('lineHeight').value,
  100. enablePageBreak: document.getElementById('enablePageBreak').checked
  101. };
  102. saveConfig(newConfig);
  103. modal.style.display = 'none';
  104. });
  105.  
  106. return modal;
  107. }
  108.  
  109. // Create and update styles based on current config
  110. function updateStyles() {
  111. const styleSheet = `
  112. /* 打印样式优化 */
  113. @media print {
  114. html, body {
  115. margin: 0 !important;
  116. padding: 0 !important;
  117. min-height: 0 !important;
  118. height: auto !important;
  119. }
  120. .print-column-container {
  121. column-count: ${CONFIG.columns} !important;
  122. column-gap: ${CONFIG.columnGap} !important;
  123. column-rule: 1px solid #ddd !important;
  124. width: 100% !important;
  125. margin: 0 !important;
  126. padding: 0 !important;
  127. min-height: 0 !important;
  128. height: auto !important;
  129. overflow: visible !important;
  130. box-sizing: border-box !important;
  131. font-size: ${CONFIG.fontSize} !important;
  132. line-height: ${CONFIG.lineHeight} !important;
  133. ${CONFIG.enablePageBreak ? '' : 'page-break-inside: avoid !important;'}
  134. }
  135. .print-column-container > * {
  136. break-inside: avoid !important;
  137. margin-bottom: ${CONFIG.paragraphSpacing} !important;
  138. max-width: 100% !important;
  139. box-sizing: border-box !important;
  140. page-break-inside: avoid !important;
  141. }
  142. .print-column-container img {
  143. max-width: 100% !important;
  144. height: auto !important;
  145. page-break-inside: avoid !important;
  146. }
  147. }
  148. `;
  149.  
  150. // Remove existing style if any
  151. const existingStyle = document.getElementById('print-layout-style');
  152. if (existingStyle) {
  153. existingStyle.remove();
  154. }
  155.  
  156. // Add new style
  157. const style = document.createElement('style');
  158. style.id = 'print-layout-style';
  159. style.textContent = styleSheet;
  160. document.head.appendChild(style);
  161. }
  162.  
  163. // Apply columns to main content
  164. function applyPrintColumns() {
  165. const mainContent = document.querySelector('.target-content') || document.body;
  166. mainContent.classList.add('print-column-container');
  167.  
  168. const printStyle = document.createElement('style');
  169. printStyle.media = 'print';
  170. printStyle.textContent = `
  171. @page {
  172. margin: 1cm !important;
  173. padding: 0 !important;
  174. size: auto !important;
  175. }
  176. `;
  177. document.head.appendChild(printStyle);
  178. }
  179.  
  180. // Initialize
  181. let lastCtrlPress = 0;
  182. const configModal = createConfigUI();
  183.  
  184. // Handle double Ctrl press
  185. document.addEventListener('keydown', (e) => {
  186. if (e.key === 'Control') {
  187. const now = Date.now();
  188. if (now - lastCtrlPress < 300) { // 300ms threshold for double press
  189. configModal.style.display = configModal.style.display === 'none' ? 'block' : 'none';
  190. }
  191. lastCtrlPress = now;
  192. }
  193. });
  194.  
  195. // Initial style application
  196. updateStyles();
  197.  
  198. // Apply columns when DOM is ready
  199. if (document.readyState === 'loading') {
  200. document.addEventListener('DOMContentLoaded', applyPrintColumns);
  201. } else {
  202. applyPrintColumns();
  203. }
  204.  
  205. // Log usage instructions to console
  206. console.log(`
  207. Multi-Column Layout Userscript Usage:
  208. -----------------------------------
  209. 1. Double-press Ctrl key to open settings
  210. 2. Adjust your preferences:
  211. - Columns: Number of columns (1-4)
  212. - Column Gap: Space between columns
  213. - Font Size: Text size in print
  214. - Paragraph Spacing: Space between paragraphs
  215. - Line Height: Text line height
  216. - Enable Page Break: Allow/prevent content breaks across pages
  217. 3. Click Save to apply changes
  218. 4. Settings are automatically saved between sessions
  219. 5. Press Ctrl+P to see the print preview with your settings
  220.  
  221. Current configuration:`, CONFIG);
  222.  
  223. })();