跳转到内容

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

勤求古训,博采众方
无编辑摘要
无编辑摘要
第1行: 第1行:
// ==UserScript==
(function () {
// @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';
     'use strict';
 
      
     // 🔊 Audio Context Manager Class
     var windowManager;
     class AudioSystem {
    var printDialog;
        constructor(options = {}) {
   
            this.options = {
    // Modernized configuration object
                latencyHint: 'interactive',
    var printOptions = {
                sampleRate: 44100,
         install: function () {
                ...options
             var $printLink = $('#t-print a');
            };
             if ($printLink.length === 0) {
            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;
                 return;
             }
             }
 
           
             try {
            $printLink
                 this.context = new AudioContextClass(this.options);
                .text('可打印版本')
                 this.setupEventListeners();
                .off('click')
                 this.log('AudioContext created');
                .on('click', function (e) {
             } catch (error) {
                    mw.loader.using([
                 console.error('AudioContext initialization failed:', error);
                        'oojs-ui-core',
                        'oojs-ui-widgets',
                        'oojs-ui-windows',
                        'mediawiki.api'
                    ]).then(printOptions.createWindow);
                    e.preventDefault();
                    e.stopPropagation();
                });
              
            // Preload resources
            mw.loader.load(['oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows']);
        },
       
        createWindow: function () {
            // Modern OOUI dialog implementation
            var PrintDialog = function (config) {
                 PrintDialog.super.call(this, config);
            };
           
            OO.inheritClass(PrintDialog, OO.ui.ProcessDialog);
           
            PrintDialog.static.name = 'printdialog';
            PrintDialog.static.title = mw.message('printdialog-title').plain();
            PrintDialog.static.actions = [
                {
                    action: 'print',
                    label: mw.message('printdialog-action-print').plain(),
                    flags: ['primary', 'progressive']
                },
                {
                    action: 'cancel',
                    label: mw.message('cancel').plain(),
                    flags: 'safe'
                }
            ];
           
            PrintDialog.prototype.initialize = function () {
                PrintDialog.super.prototype.initialize.apply(this, arguments);
               
                this.contentPanel = new OO.ui.PanelLayout({
                    padded: true,
                    expanded: false
                });
               
                this.fieldset = new OO.ui.FieldsetLayout({
                    label: mw.message('printdialog-options').plain()
                });
               
                // Dynamically create checkboxes from configuration
                printOptions.questions.forEach(function (question) {
                    if (question.type === 'checkbox') {
                        var checkbox = new OO.ui.CheckboxInputWidget({
                            selected: question.checked
                        });
                       
                        question.widget = checkbox;
                       
                        this.fieldset.addItems([
                            new OO.ui.FieldLayout(checkbox, {
                                label: mw.message(question.msgKey || question.label).plain(),
                                align: 'inline'
                            })
                        ]);
                    }
                }.bind(this));
               
                 this.contentPanel.$element.append(this.fieldset.$element);
                 this.$body.append(this.contentPanel.$element);
            };
           
            PrintDialog.prototype.getActionProcess = function (action) {
                var dialog = this;
               
                if (action === 'print') {
                    return new OO.ui.Process(function () {
                        // Gather all selected options
                        printOptions.questions.forEach(function (question) {
                            if (question.type === 'checkbox' && question.widget) {
                                printOptions[question.returnvalue] = question.widget.isSelected();
                            }
                        });
                       
                        return dialog.close({ action: action }).then(function () {
                            printOptions.prepareForPrinting();
                            window.print();
                            setTimeout(function () {
                                window.location.reload();
                            }, 500);
                        });
                    });
                }
               
                return PrintDialog.super.prototype.getActionProcess.call(this, action);
             };
           
            // Initialize window manager if needed
            if (!windowManager) {
                 windowManager = new OO.ui.WindowManager();
                windowManager.$element.css('z-index', '2000');
                $(document.body).append(windowManager.$element);
             }
             }
        }
           
 
            // Create dialog if needed
        // 🎛️ Setup state management
             if (!printDialog) {
        setupEventListeners() {
                printDialog = new PrintDialog({
             if (!this.context) return;
                    size: 'medium',
 
                    classes: ['print-dialog']
            // Monitor state changes
                 });
            this.context.onstatechange = () => {
                 this.log(`State changed: ${this.context.state}`);
                  
                  
                 if (this.context.state === 'suspended') {
                 windowManager.addWindows([printDialog]);
                     this.addActivationTriggers();
            }
           
            windowManager.openWindow(printDialog);
        },
       
        prepareForPrinting: function () {
            this.updatePrintStyles();
            this.applyCustomPrintStyles();
            this.enhancePrintFooter();
        },
       
        updatePrintStyles: function () {
            if (this.enhanced === false) return;
           
            Array.from(document.styleSheets).forEach(function (stylesheet) {
                try {
                    if (!stylesheet.media) return;
                   
                    // Handle media rules for stylesheets
                    var mediaText = stylesheet.media.mediaText || '';
                    if (mediaText.includes('print')) {
                        if (!mediaText.includes('screen')) {
                            stylesheet.disabled = true;
                        }
                    } else if (mediaText.includes('screen')) {
                        try {
                            stylesheet.media.appendMedium('print');
                        } catch (e) {
                            stylesheet.media.mediaText += ',print';
                        }
                    }
                   
                    // Handle media rules within stylesheets
                    var rules = stylesheet.cssRules || stylesheet.rules;
                    if (!rules) return;
                   
                    for (var i = 0; i < rules.length; i++) {
                        var rule = rules[i];
                        if (rule.type !== CSSRule.MEDIA_RULE || !rule.media) continue;
                       
                        var media = Array.from(rule.media);
                        if (media.includes('print') && !media.includes('screen')) {
                            stylesheet.deleteRule ? stylesheet.deleteRule(i) : stylesheet.removeRule(i);
                            i--;
                        } else if (media.includes('screen') && !media.includes('print')) {
                            try {
                                rule.media.appendMedium('print');
                            } catch (e) {
                                rule.media.mediaText += ',print';
                            }
                        }
                    }
                } catch (e) {
                     mw.log.warn('Could not process stylesheet:', e.message);
                 }
                 }
             };
             });
 
        },
             // Initial activation check
       
             if (this.context.state === 'suspended') {
        applyCustomPrintStyles: function () {
                 this.addActivationTriggers();
            var styles = [];
           
            if (this.noimages) {
                styles.push('img, .thumb, figure { display: none !important; }');
            }
              
             if (this.norefs) {
                styles.push('.references, .reference, .mw-references-wrap { display: none !important; }');
            }
           
            if (this.notoc) {
                styles.push('#toc, .toc { display: none !important; }');
            }
           
            if (this.nobackground) {
                styles.push('* { background: none !important; }');
                styles.push('body { background-color: white !important; }');
            }
           
            if (this.blacktext) {
                styles.push('* { color: black !important; }');
                styles.push('a { color: #0645ad !important; }');
            }
           
            if (styles.length) {
                var styleEl = document.createElement('style');
                styleEl.setAttribute('media', 'print');
                styleEl.textContent = styles.join('\n');
                 document.head.appendChild(styleEl);
             }
             }
         }
         },
 
          
         // 🖱️ Add user interaction triggers
         enhancePrintFooter: function () {
         addActivationTriggers() {
             var printFooter = document.querySelector('.printfooter');
             const events = ['click', 'keydown', 'touchstart'];
             if (printFooter) {
             const handler = () => {
                 var link = printFooter.querySelector('a');
                 if (this.context && this.context.state === 'suspended') {
                if (link) {
                     this.context.resume()
                     try {
                         .then(() => this.log('Audio resumed successfully'))
                         link.textContent = decodeURIComponent(link.textContent);
                         .catch(err => console.error('Resume failed:', err));
                    } catch (e) {
                         mw.log.warn('Could not decode print footer URL:', e.message);
                    }
                 }
                 }
               
                // 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();
        // Updated configuration with i18n message keys
                 source.buffer = buffer;
        questions: [
                 source.connect(this.context.destination);
             {
                 source.start();
                 msgKey: 'printdialog-option-enhance',
                 return source;
                 type: 'checkbox',
             } catch (error) {
                 checked: true,
                 console.error('Playback failed:', error);
                 returnvalue: 'enhanced'
                 return null;
            },
            {
                msgKey: 'printdialog-option-noimages',
                 type: 'checkbox',
                checked: false,
                returnvalue: 'noimages'
             },
            {
                 msgKey: 'printdialog-option-norefs',
                type: 'checkbox',
                checked: false,
                returnvalue: 'norefs'
            },
            {
                 msgKey: 'printdialog-option-notoc',
                type: 'checkbox',
                checked: false,
                returnvalue: 'notoc'
            },
            {
                msgKey: 'printdialog-option-nobackground',
                type: 'checkbox',
                checked: false,
                returnvalue: 'nobackground'
            },
            {
                msgKey: 'printdialog-option-blacktext',
                type: 'checkbox',
                checked: true,
                returnvalue: 'blacktext'
             }
             }
        ]
    };
   
    // Localization messages
    mw.messages.set({
        'printdialog-title': '打印此页面',
        'printdialog-options': '打印选项',
        'printdialog-action-print': '打印',
        'printdialog-option-enhance': '隐藏界面元素',
        'printdialog-option-noimages': '隐藏图像',
        'printdialog-option-norefs': '隐藏引用',
        'printdialog-option-notoc': '隐藏目录',
        'printdialog-option-nobackground': '删除背景(您的浏览器可能会或可能不会覆盖此背景)',
        'printdialog-option-blacktext': '强制所有文本为黑色'
    });
   
    // Run installation after page load
    mw.hook('wikipage.content').add(function () {
        if (mw.config.get('wgNamespaceNumber') >= 0) {
            printOptions.install();
         }
         }
    }
    // 🚀 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);
     });
     });
 
}());
})();

2025年11月1日 (六) 21:05的版本

(function () {
    'use strict';
    
    var windowManager;
    var printDialog;
    
    // Modernized configuration object
    var printOptions = {
        install: function () {
            var $printLink = $('#t-print a');
            if ($printLink.length === 0) {
                return;
            }
            
            $printLink
                .text('可打印版本')
                .off('click')
                .on('click', function (e) {
                    mw.loader.using([
                        'oojs-ui-core',
                        'oojs-ui-widgets',
                        'oojs-ui-windows',
                        'mediawiki.api'
                    ]).then(printOptions.createWindow);
                    e.preventDefault();
                    e.stopPropagation();
                });
            
            // Preload resources
            mw.loader.load(['oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows']);
        },
        
        createWindow: function () {
            // Modern OOUI dialog implementation
            var PrintDialog = function (config) {
                PrintDialog.super.call(this, config);
            };
            
            OO.inheritClass(PrintDialog, OO.ui.ProcessDialog);
            
            PrintDialog.static.name = 'printdialog';
            PrintDialog.static.title = mw.message('printdialog-title').plain();
            PrintDialog.static.actions = [
                { 
                    action: 'print',
                    label: mw.message('printdialog-action-print').plain(),
                    flags: ['primary', 'progressive']
                },
                {
                    action: 'cancel',
                    label: mw.message('cancel').plain(),
                    flags: 'safe'
                }
            ];
            
            PrintDialog.prototype.initialize = function () {
                PrintDialog.super.prototype.initialize.apply(this, arguments);
                
                this.contentPanel = new OO.ui.PanelLayout({
                    padded: true,
                    expanded: false
                });
                
                this.fieldset = new OO.ui.FieldsetLayout({
                    label: mw.message('printdialog-options').plain()
                });
                
                // Dynamically create checkboxes from configuration
                printOptions.questions.forEach(function (question) {
                    if (question.type === 'checkbox') {
                        var checkbox = new OO.ui.CheckboxInputWidget({
                            selected: question.checked
                        });
                        
                        question.widget = checkbox;
                        
                        this.fieldset.addItems([
                            new OO.ui.FieldLayout(checkbox, {
                                label: mw.message(question.msgKey || question.label).plain(),
                                align: 'inline'
                            })
                        ]);
                    }
                }.bind(this));
                
                this.contentPanel.$element.append(this.fieldset.$element);
                this.$body.append(this.contentPanel.$element);
            };
            
            PrintDialog.prototype.getActionProcess = function (action) {
                var dialog = this;
                
                if (action === 'print') {
                    return new OO.ui.Process(function () {
                        // Gather all selected options
                        printOptions.questions.forEach(function (question) {
                            if (question.type === 'checkbox' && question.widget) {
                                printOptions[question.returnvalue] = question.widget.isSelected();
                            }
                        });
                        
                        return dialog.close({ action: action }).then(function () {
                            printOptions.prepareForPrinting();
                            window.print();
                            setTimeout(function () {
                                window.location.reload();
                            }, 500);
                        });
                    });
                }
                
                return PrintDialog.super.prototype.getActionProcess.call(this, action);
            };
            
            // Initialize window manager if needed
            if (!windowManager) {
                windowManager = new OO.ui.WindowManager();
                windowManager.$element.css('z-index', '2000');
                $(document.body).append(windowManager.$element);
            }
            
            // Create dialog if needed
            if (!printDialog) {
                printDialog = new PrintDialog({
                    size: 'medium',
                    classes: ['print-dialog']
                });
                
                windowManager.addWindows([printDialog]);
            }
            
            windowManager.openWindow(printDialog);
        },
        
        prepareForPrinting: function () {
            this.updatePrintStyles();
            this.applyCustomPrintStyles();
            this.enhancePrintFooter();
        },
        
        updatePrintStyles: function () {
            if (this.enhanced === false) return;
            
            Array.from(document.styleSheets).forEach(function (stylesheet) {
                try {
                    if (!stylesheet.media) return;
                    
                    // Handle media rules for stylesheets
                    var mediaText = stylesheet.media.mediaText || '';
                    if (mediaText.includes('print')) {
                        if (!mediaText.includes('screen')) {
                            stylesheet.disabled = true;
                        }
                    } else if (mediaText.includes('screen')) {
                        try {
                            stylesheet.media.appendMedium('print');
                        } catch (e) {
                            stylesheet.media.mediaText += ',print';
                        }
                    }
                    
                    // Handle media rules within stylesheets
                    var rules = stylesheet.cssRules || stylesheet.rules;
                    if (!rules) return;
                    
                    for (var i = 0; i < rules.length; i++) {
                        var rule = rules[i];
                        if (rule.type !== CSSRule.MEDIA_RULE || !rule.media) continue;
                        
                        var media = Array.from(rule.media);
                        if (media.includes('print') && !media.includes('screen')) {
                            stylesheet.deleteRule ? stylesheet.deleteRule(i) : stylesheet.removeRule(i);
                            i--;
                        } else if (media.includes('screen') && !media.includes('print')) {
                            try {
                                rule.media.appendMedium('print');
                            } catch (e) {
                                rule.media.mediaText += ',print';
                            }
                        }
                    }
                } catch (e) {
                    mw.log.warn('Could not process stylesheet:', e.message);
                }
            });
        },
        
        applyCustomPrintStyles: function () {
            var styles = [];
            
            if (this.noimages) {
                styles.push('img, .thumb, figure { display: none !important; }');
            }
            
            if (this.norefs) {
                styles.push('.references, .reference, .mw-references-wrap { display: none !important; }');
            }
            
            if (this.notoc) {
                styles.push('#toc, .toc { display: none !important; }');
            }
            
            if (this.nobackground) {
                styles.push('* { background: none !important; }');
                styles.push('body { background-color: white !important; }');
            }
            
            if (this.blacktext) {
                styles.push('* { color: black !important; }');
                styles.push('a { color: #0645ad !important; }');
            }
            
            if (styles.length) {
                var styleEl = document.createElement('style');
                styleEl.setAttribute('media', 'print');
                styleEl.textContent = styles.join('\n');
                document.head.appendChild(styleEl);
            }
        },
        
        enhancePrintFooter: function () {
            var printFooter = document.querySelector('.printfooter');
            if (printFooter) {
                var link = printFooter.querySelector('a');
                if (link) {
                    try {
                        link.textContent = decodeURIComponent(link.textContent);
                    } catch (e) {
                        mw.log.warn('Could not decode print footer URL:', e.message);
                    }
                }
            }
        },
        
        // Updated configuration with i18n message keys
        questions: [
            {
                msgKey: 'printdialog-option-enhance',
                type: 'checkbox',
                checked: true,
                returnvalue: 'enhanced'
            },
            {
                msgKey: 'printdialog-option-noimages',
                type: 'checkbox',
                checked: false,
                returnvalue: 'noimages'
            },
            {
                msgKey: 'printdialog-option-norefs',
                type: 'checkbox',
                checked: false,
                returnvalue: 'norefs'
            },
            {
                msgKey: 'printdialog-option-notoc',
                type: 'checkbox',
                checked: false,
                returnvalue: 'notoc'
            },
            {
                msgKey: 'printdialog-option-nobackground',
                type: 'checkbox',
                checked: false,
                returnvalue: 'nobackground'
            },
            {
                msgKey: 'printdialog-option-blacktext',
                type: 'checkbox',
                checked: true,
                returnvalue: 'blacktext'
            }
        ]
    };
    
    // Localization messages
    mw.messages.set({
        'printdialog-title': '打印此页面',
        'printdialog-options': '打印选项',
        'printdialog-action-print': '打印',
        'printdialog-option-enhance': '隐藏界面元素',
        'printdialog-option-noimages': '隐藏图像',
        'printdialog-option-norefs': '隐藏引用',
        'printdialog-option-notoc': '隐藏目录',
        'printdialog-option-nobackground': '删除背景(您的浏览器可能会或可能不会覆盖此背景)',
        'printdialog-option-blacktext': '强制所有文本为黑色'
    });
    
    // Run installation after page load
    mw.hook('wikipage.content').add(function () {
        if (mw.config.get('wgNamespaceNumber') >= 0) {
            printOptions.install();
        }
    });
}());