LLWiki正在建设中,欢迎加入我们

MediaWiki:Gadget-contentBackup.js

来自LLWiki
跳转到导航 跳转到搜索

注意:在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Internet Explorer:按住Ctrl的同时单击刷新,或按Ctrl-F5
  • Opera:前往菜单 → 设置(Mac为Opera → Preferences),然后隐私和安全 → 清除浏览数据 → 缓存的图片和文件
//<nowiki>
// 由ResourceLoader直接调用,不可使用ES6语法
/**
 * @Function: 点击“提交编辑、显示预览、显示更改”中任意一个按钮,或在编辑页面每隔一段时间自动备份当前的编辑。
              备份会保存一段时间后自动清除。支持Wikiplus和代码编辑器。
 * @Dependencies: ext.gadget.SettingsDialog, localforage
 * @Source: [[moegirl:User:东东君/js/contentBackup.js]]
 * @EditedBy: [[User:Bhsd]]
 */
"use strict";
/* global OO, wgULS, localforage */
// 默认只用于桌面版、备份保存12小时、每隔30分钟自动更新备份
mw.gadgets.contentBackup = $.extend({range: ['vector'], exp: 12, stay: 30},
    mw.storage.getObject( 'gadget-contentBackup' ),
    mw.gadgets.contentBackup
);
const action = mw.config.get( 'wgAction' ),
    isEditable = mw.config.get( 'wgIsProbablyEditable' ),
    skin = mw.config.get( 'skin' ),
    isWikiplus = action == 'view' && (mw.isModule('Wikiplus', true) || mw.isModule('mobile-Wikiplus', true)),
    settings = mw.gadgets.contentBackup;
if (isEditable && settings.range.includes( skin ) && (['edit', 'submit'].includes(action) || isWikiplus)) {
    var codeEditor, // 实时更新的Ace Editor Session
        backup = '', // 因为localforage提取backup是个Promise,这里先初始化
        expList = mw.storage.getObject( 'LLWiki-contentBackup-exp' ) || {}; // 单独存储备份过期时间,这是个Object
    const id = mw.config.get( 'wgArticleId' ).toString(), // 所有新建页面共用备份
        btns = '#wpSaveWidget, #wpPreviewWidget, #wpDiffWidget, #wpTemplateSandboxPreview', // MW原生编辑页面
        editor = '#wpTextbox1, #Wikiplus-Quickedit', // 部分编辑器需动态生成,所以这里只保存选择器
        expArray = Object.entries( expList ),
        expired = mw.now() - settings.exp * 1000 * 3600,
        stay = settings.stay * 1000 * 60; // 通过设置改动stay时若立即生效会造成bug

    // 1. 设置本地化消息
    mw.messages.set( wgULS({
        'gadget-cb-label': '编辑内容自动备份', 'gadget-cb-range': '使用范围', 'gadget-cb-d': '桌面版',
        'gadget-cb-m': '手机版', 'gadget-cb-rhelp': '可用于代码编辑器和Wikiplus小工具。', 'gadget-cb-text': '还原备份',
        'gadget-cb-exp': '备份有效期(小时)', 'gadget-cb-stay': '自动备份间隔(分)', 'gadget-cb-success': '已还原备份!',
        'gadget-cb-shelp': "仅用于原生编辑页面。值为'0'时不会自动更新备份,变动后需刷新页面才会生效。"
    }, {
        'gadget-cb-label': '編輯內容自動備份', 'gadget-cb-range': '使用範圍', 'gadget-cb-d': '桌面版',
        'gadget-cb-m': '手機版', 'gadget-cb-rhelp': '可用於代碼編輯器和Wikiplus小工具。', 'gadget-cb-text': '還原備份',
        'gadget-cb-exp': '備份有效期(小時)', 'gadget-cb-stay': '自動備份間隔(分)', 'gadget-cb-success': '已還原備份!',
        'gadget-cb-shelp': "僅用於原生編輯頁面。值為'0'時不會自動更新備份,變動後需重新整理頁面才會生效。"
    }) );

    // 2. 小工具设置
    mw.settingsDialog.addTab({name: 'contentBackup', label: 'gadget-cb-label', items: [
        {key: 'range', type: 'CheckboxMultiselect', label: 'gadget-cb-range', help: mw.msg( 'gadget-cb-rhelp' ),
            config: {options: [
                {data: 'vector', label: mw.msg( 'gadget-cb-d' )}, {data: 'minerva', label: mw.msg( 'gadget-cb-m' )}
            ]}
        }, {key: 'stay', type: 'Number', label: 'gadget-cb-stay', help: mw.msg('gadget-cb-shelp'),
            config: {min: 0, buttonStep: 5, required: true}
        }, {key: 'exp', type: 'Number', label: 'gadget-cb-exp', config: {min: 1, buttonStep: 1, required: true}}
    ], help: '编辑内容备份'});

    // 3. 核心函数
    const loadBackup = function() { // 加载备份函数
        // CodeEditor需特殊处理
        if ($( '.codeEditor-ui-toolbar' ).length) { codeEditor.setValue( backup ); }
        else { $(editor).val( backup ); }
        mw.notify( mw.msg('gadget-cb-success'), {type: 'success'} );
        update();
    },
        saveBackup = function() { // 保存备份函数
        // CodeEditor需特殊处理
        if ($( '.codeEditor-ui-toolbar' ).length) { backup = codeEditor.getValue(); }
        else { backup = $(editor).val(); }
        expList[id] = mw.now();
        mw.storage.setObject('LLWiki-contentBackup-exp', expList);
        localforage.setItem(id, backup);
        update();
    },
        // 自动更新函数,不支持Wikiplus
        update = isWikiplus || stay === 0 ? function() {} : mw.util.debounce(stay, function() { // jshint ignore: line
        saveBackup();
        console.log('备份自动更新于' + new Date().toLocaleTimeString( 'zh' ));
    }),
        btn = isWikiplus ? {setDisabled: function() {}} :
        new OO.ui.ButtonWidget({label: mw.msg('gadget-cb-text'), disabled: true}).on('click', loadBackup);
    
    mw.loader.getScript( 'https://cdn.jsdelivr.net/npm/localforage/dist/localforage.min.js' ).then(function() {
        localforage.config({name: 'LLWiki-contentBackup'});
        // 4. 先更新备份
        if (expArray.length) {
            expArray.filter(function(ele) { return ele[1] <= expired; })
                .forEach(function(ele) { localforage.removeItem( ele[0] ); });
            expList = Object.fromEntries( expArray.filter(function(ele) { return ele[1] > expired; }) );
            mw.storage.setObject('LLWiki-contentBackup-exp', expList);
        } else { mw.storage.remove( 'LLWiki-contentBackup' ); } // 移除旧版小工具的备份存档
        if (expList[id]) {
            localforage.getItem(id, function(_, item) {
                backup = item;
                btn.setDisabled( !backup );
            });
        }

        // 5. 初始化延时保存备份功能
        update();

        // 6. 添加备份按钮和按键保存备份功能
        if (isWikiplus) {
            const $btnPro = $('<button>', {text: mw.msg('gadget-cb-text')}).click( loadBackup );
            mw.hook( 'wikiplus.dialog' ).add(function() { // Wikiplus需动态添加备份按钮
                const $previewBtn = $('#Wikiplus-Quickedit-Preview-Submit');
                if ($previewBtn.next( 'button' ).length) { return; } // 防止按钮已存在
                console.log('Hook: wikiplus.dialog, 开始添加备份按钮');
                const $btn = $btnPro.clone( true ).prop('disabled', !backup).insertAfter( $previewBtn );
                // Wikiplus的上层为body,delegate效率太低
                $('#Wikiplus-Quickedit-Submit, #Wikiplus-Quickedit-Preview-Submit').mousedown(function() {
                    saveBackup();
                    $btn.prop('disabled', !backup);
                });
            });
        } else {
            $(function() { // 只添加一次按钮
                btn.$element.insertAfter( '#wpDiffWidget' );
                // #wpTemplateSandboxPreview可能由小工具生成,这里避免麻烦直接delegate
                $('.editOptions').on('mousedown', btns, function() {
                    saveBackup();
                    btn.setDisabled( !backup );
                });
            });
        }
    }, function() { console.error( '无法获得localforage!' ); });

    // 7. 更新Ace Editor Session
    mw.hook( 'codeEditor.configure' ).add(function(session) {
        console.log('Hook: codeEditor.configure, 更新CodeEditor编辑器');
        codeEditor = session;
    });
}
//</nowiki>
// [[category:作为模块的小工具]] [[category:编辑工具]] [[category:需要用户权限的小工具]] [[category:桌面版小工具]] [[category:手机版小工具]]
// {{DEFAULTSORT:contentBackup.js}}