跳转到内容

MediaWiki:Gadget-PrintOptions.js:修订间差异

勤求古训,博采众方
无编辑摘要
无编辑摘要
第1行: 第1行:
// ==UserScript==
// ==UserScript==
// @name        MediaWiki打印增强
// @name        Safe Web Audio Implementation
// @description  高级打印选项(优化布局/隐藏图片等)
// @namespace    https://github.com/
// @namespace    https://github.com/yourname/
// @version      1.0
// @version      2.0
// @description  Proper AudioContext initialization with full error handling
// @author      You
// @match        *://*/*
// @match        *://*/*
// @grant        none
// @grant        none
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
// @require      https://cdn.jsdelivr.net/npm/web-audio-api-shim@0.2.6/build/WebAudioAPI.min.js
// ==/UserScript==
// ==/UserScript==


第12行: 第13行:
     'use strict';
     'use strict';


     // ============== 核心配置 ==============
     // 🔊 Audio Context Manager Class
     const PrintEnhancer = {
     class AudioSystem {
         // 默认配置
         constructor(options = {}) {
        config: {
            this.options = {
            enhanced: true,
                latencyHint: 'interactive',
            noimages: false,
                sampleRate: 44100,
            norefs: false,
                ...options
             notoc: false,
             };
             nobackground: false,
             this.context = null;
             blacktext: true
             this.init();
         },
         }


         // 对话框选项
         // 🔍 Detect supported AudioContext class
         questions: [
         static getAudioContextClass() {
             {
             const prefixes = ['', 'webkit', 'moz', 'ms'];
                type: 'checkbox',
             for (const prefix of prefixes) {
                name: 'enhanced',
                 const name = prefix ? `${prefix}AudioContext` : 'AudioContext';
                label: '优化打印布局',
                 if (window[name]) return window[name];
                help: '隐藏编辑按钮等非必要元素'
            },
            {
                type: 'checkbox',
                name: 'noimages',
                label: '隐藏所有图片'
             },
            {
                 type: 'checkbox',
                name: 'norefs',
                label: '隐藏参考文献'
            },
            {
                type: 'checkbox',
                name: 'notoc',
                label: '隐藏目录'
            },
            {
                type: 'checkbox',
                 name: 'nobackground',
                label: '移除背景色',
                help: '节省墨水,但可能影响部分内容可见性'
            },
            {
                type: 'checkbox',
                name: 'blacktext',
                label: '强制纯黑色文字'
             }
             }
         ],
            return null;
         }


         // ============== 初始化 ==============
         // 🏗️ Initialize audio system
         init() {
         init() {
             const $printLink = $('#t-print a, .vector-menu-tabs a[href*="printable=yes"]').first();
             const AudioContextClass = AudioSystem.getAudioContextClass();
             if (!$printLink.length) {
             if (!AudioContextClass) {
                 console.warn('找不到打印链接');
                 console.warn('Web Audio API not supported');
                 return;
                 return;
             }
             }


             $printLink
             try {
                 .text('可打印版本')
                 this.context = new AudioContextClass(this.options);
                .off('click.mwprint')
                 this.setupEventListeners();
                 .on('click.mwprint', (e) => {
                 this.log('AudioContext created');
                    e.preventDefault();
            } catch (error) {
                    this.openDialog();
                console.error('AudioContext initialization failed:', error);
                 });
        },
 
        // ============== 对话框控制 ==============
        openDialog() {
            // 动态加载OOUI库
            if (!window.OO) {
                mw.loader.using(['oojs-ui', 'oojs-ui-windows']).then(() => {
                    this._createDialog();
                }).catch(err => {
                    console.error('加载OOUI失败:', err);
                    alert('打印功能初始化失败,请刷新页面重试');
                });
            } else {
                this._createDialog();
             }
             }
         },
         }


         _createDialog() {
         // 🎛️ Setup state management
            // 1. 创建对话框类
        setupEventListeners() {
            function PrintDialog(config) {
            if (!this.context) return;
                PrintDialog.super.call(this, config);
            }
            OO.inheritClass(PrintDialog, OO.ui.ProcessDialog);


             // 2. 对话框配置
             // Monitor state changes
             PrintDialog.static.name = 'PrintEnhancerDialog';
             this.context.onstatechange = () => {
            PrintDialog.static.title = '打印设置';
                this.log(`State changed: ${this.context.state}`);
            PrintDialog.static.actions = [
               
                {
                if (this.context.state === 'suspended') {
                    action: 'print',
                     this.addActivationTriggers();
label: '打印',
                    flags: ['primary', 'progressive']
                },
                {  
                     action: 'cancel',
                    label: '取消',
                    flags: 'safe'
                 }
                 }
            ];
            // 3. 构建对话框内容
            PrintDialog.prototype.initialize = function() {
                PrintDialog.super.prototype.initialize.apply(this, arguments);
               
                const panel = new OO.ui.PanelLayout({
                    padded: true,
                    expanded: false
                });
               
                const fieldset = new OO.ui.FieldsetLayout({
                    label: '打印选项'
                });
                // 添加所有复选框
                PrintEnhancer.questions.forEach(q => {
                    const checkbox = new OO.ui.CheckboxInputWidget({
                        selected: PrintEnhancer.config[q.name]
                    });
                   
                    const field = new OO.ui.FieldLayout(checkbox, {
                        label: q.label,
                        align: 'inline',
                        help: q.help ? new OO.ui.HtmlSnippet(q.help) : null
                    });
                   
                    fieldset.addItems([field]);
                    this[q.name] = checkbox; // 保存引用
                });
                panel.$element.append(fieldset.$element);
                this.$body.append(panel.$element);
             };
             };


             // 4. 处理按钮动作
             // Initial activation check
             PrintDialog.prototype.getActionProcess = function(action) {
             if (this.context.state === 'suspended') {
                const dialog = this;
                 this.addActivationTriggers();
                return new OO.ui.Process(() => {
                    if (action === 'print') {
                        // 保存用户选择
                        PrintEnhancer.questions.forEach(q => {
                            PrintEnhancer.config[q.name] = dialog[q.name].isSelected();
                        });
                    }
                    dialog.close({ action });
                 });
            };
 
            // 5. 创建窗口管理器
            if (!this.windowManager) {
                this.windowManager = new OO.ui.WindowManager();
                $(document.body).append(this.windowManager.$element);
             }
             }
        }


            // 6. 显示对话框
        // 🖱️ Add user interaction triggers
             const dialog = new PrintDialog({ size: 'medium' });
        addActivationTriggers() {
            this.windowManager.addWindows([dialog]);
             const events = ['click', 'keydown', 'touchstart'];
             this.windowManager.openWindow(dialog).then(() => {
             const handler = () => {
                 if (dialog.action === 'print') {
                 if (this.context && this.context.state === 'suspended') {
                     this.applyPrintStyles();
                     this.context.resume()
                    setTimeout(() => window.print(), 300);
                        .then(() => this.log('Audio resumed successfully'))
                        .catch(err => console.error('Resume failed:', err));
                 }
                 }
             });
               
         },
                // Remove after first activation
                events.forEach(e => document.removeEventListener(e, handler));
             };
 
            events.forEach(e => document.addEventListener(e, handler));
         }


         // ============== 打印样式应用 ==============
         // 📝 Logging helper
         applyPrintStyles() {
         log(message) {
             const cssRules = [];
             console.log(`[AudioSystem] ${message}`);
            const c = this.config;
        }


            if (c.enhanced) cssRules.push(`
        // 🎵 Safe audio playback
                .noprint, #siteNotice, .mw-editsection,
        playBuffer(buffer) {
                .mw-indicators, .firstHeading .mw-headline {
             if (!this.context || this.context.state !== 'running') {
                    display: none !important;
                console.warn('Audio not ready');
                }
                return null;
            `);
             }
             if (c.noimages) cssRules.push('img, video, .video-container { display: none !important; }');
            if (c.norefs) cssRules.push('sup.reference, .references { display: none !important; }');
            if (c.notoc) cssRules.push('#toc, .toc { display: none !important; }');
            if (c.nobackground) cssRules.push('body { background: white !important; }');
             if (c.blacktext) cssRules.push('body, body * { color: black !important; }');


             const styleId = 'mw-print-styles';
             try {
            let style = document.getElementById(styleId);
                const source = this.context.createBufferSource();
             if (!style) {
                source.buffer = buffer;
                 style = document.createElement('style');
                source.connect(this.context.destination);
                 style.id = styleId;
                source.start();
                document.head.appendChild(style);
                return source;
             } catch (error) {
                 console.error('Playback failed:', error);
                 return null;
             }
             }
            style.textContent = `@media print { ${cssRules.join('')} }`;
         }
         }
     };
     }
 
    // 🚀 Startup sequence
    document.addEventListener('DOMContentLoaded', () => {
        const audioSystem = new AudioSystem({
            latencyHint: 'balanced',
            sampleRate: 48000
        });


    // ============== 自动启动 ==============
        // Example usage
    $(document).ready(function() {
        setTimeout(() => {
        // 确保在DOM加载后运行
            if (audioSystem.context) {
        setTimeout(() => PrintEnhancer.init(), 300);
                // Load and play dummy sound
                const buffer = audioSystem.context.createBuffer(
                    1,
                    audioSystem.context.sampleRate * 0.5,
                    audioSystem.context.sampleRate
                );
                audioSystem.playBuffer(buffer);
            }
        }, 3000);
     });
     });


    // 兼容皮肤动态加载
    mw.hook('wikipage.content').add(function() {
        PrintEnhancer.init();
    });
})();
})();

2025年11月1日 (六) 20:36的版本

// ==UserScript==
// @name         Safe Web Audio Implementation
// @namespace    https://github.com/
// @version      1.0
// @description  Proper AudioContext initialization with full error handling
// @author       You
// @match        *://*/*
// @grant        none
// @require      https://cdn.jsdelivr.net/npm/web-audio-api-shim@0.2.6/build/WebAudioAPI.min.js
// ==/UserScript==

(function() {
    'use strict';

    // 🔊 Audio Context Manager Class
    class AudioSystem {
        constructor(options = {}) {
            this.options = {
                latencyHint: 'interactive',
                sampleRate: 44100,
                ...options
            };
            this.context = null;
            this.init();
        }

        // 🔍 Detect supported AudioContext class
        static getAudioContextClass() {
            const prefixes = ['', 'webkit', 'moz', 'ms'];
            for (const prefix of prefixes) {
                const name = prefix ? `${prefix}AudioContext` : 'AudioContext';
                if (window[name]) return window[name];
            }
            return null;
        }

        // 🏗️ Initialize audio system
        init() {
            const AudioContextClass = AudioSystem.getAudioContextClass();
            if (!AudioContextClass) {
                console.warn('Web Audio API not supported');
                return;
            }

            try {
                this.context = new AudioContextClass(this.options);
                this.setupEventListeners();
                this.log('AudioContext created');
            } catch (error) {
                console.error('AudioContext initialization failed:', error);
            }
        }

        // 🎛️ Setup state management
        setupEventListeners() {
            if (!this.context) return;

            // Monitor state changes
            this.context.onstatechange = () => {
                this.log(`State changed: ${this.context.state}`);
                
                if (this.context.state === 'suspended') {
                    this.addActivationTriggers();
                }
            };

            // Initial activation check
            if (this.context.state === 'suspended') {
                this.addActivationTriggers();
            }
        }

        // 🖱️ Add user interaction triggers
        addActivationTriggers() {
            const events = ['click', 'keydown', 'touchstart'];
            const handler = () => {
                if (this.context && this.context.state === 'suspended') {
                    this.context.resume()
                        .then(() => this.log('Audio resumed successfully'))
                        .catch(err => console.error('Resume failed:', err));
                }
                
                // Remove after first activation
                events.forEach(e => document.removeEventListener(e, handler));
            };

            events.forEach(e => document.addEventListener(e, handler));
        }

        // 📝 Logging helper
        log(message) {
            console.log(`[AudioSystem] ${message}`);
        }

        // 🎵 Safe audio playback
        playBuffer(buffer) {
            if (!this.context || this.context.state !== 'running') {
                console.warn('Audio not ready');
                return null;
            }

            try {
                const source = this.context.createBufferSource();
                source.buffer = buffer;
                source.connect(this.context.destination);
                source.start();
                return source;
            } catch (error) {
                console.error('Playback failed:', error);
                return null;
            }
        }
    }

    // 🚀 Startup sequence
    document.addEventListener('DOMContentLoaded', () => {
        const audioSystem = new AudioSystem({
            latencyHint: 'balanced',
            sampleRate: 48000
        });

        // Example usage
        setTimeout(() => {
            if (audioSystem.context) {
                // Load and play dummy sound
                const buffer = audioSystem.context.createBuffer(
                    1, 
                    audioSystem.context.sampleRate * 0.5, 
                    audioSystem.context.sampleRate
                );
                audioSystem.playBuffer(buffer);
            }
        }, 3000);
    });

})();