2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

User:東東君/common.js

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索

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

  • Firefox/Safari:按住“Shift”的同时单击“刷新”,或按“Ctrl-F5”或“Ctrl-R”(Mac为“⌘-R”)
  • Google Chrome:按“Ctrl-Shift-R”(Mac为“⌘-Shift-R”)
  • Internet Explorer:按住“Ctrl”的同时单击“刷新”,或按“Ctrl-F5”
  • Opera:在“工具→首选项”中清除缓存
如果您已登录但该页面出现未登录状态,请尝试在地址栏的地址最后添加代码?_=1来访问最新页面。
添加代码后的本页地址如下:-{R|https://moegirl.icu/User:%E6%9D%B1%E6%9D%B1%E5%90%9B/common.js?_=1}-
// Wikiplus快速替换
// mw.loader.load('/index.php?title=User:東東君/js/Wikiplus-replace.js&action=raw&ctype=text/javascript')
// 查找与替换
mw.loader.load('/index.php?title=User:東東君/js/replace.js&action=raw&ctype=text/javascript')
// 标签补全
mw.loader.load('/index.php?title=User:東東君/js/pair.js&action=raw&ctype=text/javascript')
// 实时通知
// mw.loader.load('/index.php?title=User:東東君/js/notification.js&action=raw&ctype=text/javascript')
// 代码生成按钮
mw.loader.load('/index.php?title=User:東東君/js/charinsert.js&action=raw&ctype=text/javascript')
// 编辑内容备份
mw.loader.load('/index.php?title=User:東東君/js/contentBackup.js&action=raw&ctype=text/javascript')
// 歌词注音
mw.loader.load('/index.php?title=User:東東君/js/ruby.js&action=raw&ctype=text/javascript')
// 快速对比版本差异 By: User:Nzh21
mw.loader.load('/index.php?title=User:Nzh21/js/QuickDiff.js&action=raw&ctype=text/javascript')
// 小工具集
mw.loader.load('/index.php?title=User:東東君/js/utils.js&action=raw&ctype=text/javascript')
// 上传工具
mw.loader.load('/index.php?title=User:東東君/js/uploader.js&action=raw&ctype=text/javascript')

// 摘要锁
// mw.loader.load('/index.php?title=User:東東君/js/lockSummary.js&action=raw&ctype=text/javascript')

// api测试沙盒
// mw.loader.load('/index.php?title=User:東東君/apiTest.js&action=raw&ctype=text/javascript')

mw.loader.load('https://cdn.jsdelivr.net/gh/koharubiyori/moegirlMMDPreviewerProducts/uploader.js')
// window.RLQ.push(function() {
//     window.__WIDGET_MMD_PREVIEWER_WORKER_PATH = 'https://' + location.hostname + mw.config.get("wgScriptPath") + '/index.php?title=MediaWiki:MMDPreviewerForMoegirl.worker.js&action=raw&ctype=text/javascript';
// 	$.getScript('https://zh.moegirl.org.cn'+mw.config.get("wgScriptPath")+'/index.php?title=MediaWiki:MMDPreviewerForMoegirl.main.js&action=raw&ctype=text/javascript').then(function() { $(window.__mmdPreviewerWidgetInit) })
// })

  /*
    注意:该插件必须依附于Wikiplus才能生效。
    
    载入后将在Wikiplus快速编辑的界面中添加一个“+”加号按钮,点击后可以新建快速替换的方案,完成后将生成一个按钮。
    在名称栏中,输入#号后面的文字将作为摘要使用,在执行匹配成功后将自动把摘要的文字置于编辑摘要栏中。
    在替换栏中可以使用 _@br_ 来指代换行,无论是否为正则模式。
    左键点击按钮执行预先设置好的替换,右键点击按钮删除该替换方案。
    
    注意:替换方案保存在当前浏览器中,而不是帐号内,若更换浏览器、更换电脑或清除缓存等,替换方案将不会同步。
  */

/**
  @typedef {Object} Patterns
  @prop {string} name
  @prop {string} pattern
  @prop {string} replaceVal
  @prop {boolean} useRegex
  @prop {string} summary
*/

var LOCAL_STORAGE_NAMESPACE = 'quickEdit-replace:'
var LOCAL_STORAGE_PATTERNS = LOCAL_STORAGE_NAMESPACE + 'patterns'

var patternManager = {
  /**
   * @type {Patterns[]}
   */
  patterns: JSON.parse(localStorage.getItem(LOCAL_STORAGE_PATTERNS) || '[]'),

  update: function() {
    localStorage.setItem(LOCAL_STORAGE_PATTERNS, JSON.stringify(this.patterns))
    renderButtons()
  },

  /**
   * @param {Object} options
   * @param {string} options.name
   * @param {string} options.pattern
   * @param {string} options.replaceVal
   * @param {boolean} options.useRegex
   * @param {string} [options.summary = ''] 
   */
  add: function(options) {
    if (options.useRegex) {
      try {
        new RegExp(options.pattern, 'g')
      } catch(e) {
        return false
      }
    }
    
    options.summary = options.summary || ''

    var foundIndex = this.patterns.find(function(item) { return item.name === options.name })
    if (foundIndex) {
      // 如果name相同的,直接覆盖那一条数据
      this.patterns[foundIndex] = options
      this.update()
      return 2
    } else {
      // 如果没有,push一个新的
      this.patterns.push(options)
      this.update()
      return 1
    }
  },

  /**
   * @param {string} name 
   */
  remove: function(name) {
    var foundIndex = this.patterns.findIndex(function(item) { return item.name === name })
    this.patterns.splice(foundIndex, 1)
    this.update()
  }
}

function renderButtons() {
  var buttons = patternManager.patterns.map(function(item) {
    var button = $('<div class="Wikiplus-Btn quickEdit-replace__replaceBtn">')
      .attr('title', item.summary)
      .data('name', item.name)
      .data('pattern', item.pattern)
      .data('useRegex', item.useRegex)
      .data('replaceVal', item.replaceVal)
    
    button.append($('<span>').text(item.name))
      .click(function(e) {
        if (e.target === this) {
          var pattern = $(this).data('pattern')
          var useRegex = $(this).data('useRegex')
          var replaceVal = $(this).data('replaceVal')
          
          if (!useRegex) {
            pattern = pattern.replace(/([\\\(\)\[\]\{\}\+\.\*\^\$\!\?\|])/g,'\\$1')
          }
    
          editorManager.replace(new RegExp(pattern, 'g'), replaceVal)
        }
      })

    var editBtn = $('<div class="quickEdit-replace__editPattern">').text('修改')
      .click(function() {
        var name = button.data('name')
        var pattern = button.data('pattern')
        var summary = button.attr('title')
        var useRegex = button.data('useRegex')
        var replaceVal = button.data('replaceVal')
        
        addPatternDialogManager.show({
          name: name,
          pattern: pattern,
          summary: summary,
          useRegex: useRegex,
          replaceVal: replaceVal
        })
      })

    var removeBtn = $('<div class="quickEdit-replace__removePattern">').text('×')
      .click((function(name){
        return function() {
          patternManager.remove(name)
          mw.notify('删除成功')
        }
      })(item.name))

    button.append(editBtn, removeBtn)

    return button
  })

  var buttonContainer = $('.quickEdit-replace__replaceButtonContainer')
  buttonContainer.empty().append.apply(buttonContainer, buttons)
}

var editorManager = {
  textarea: null,
  replaceBackup: null,

  /**
   * @param {RegExp} regex 
   * @param {string} replaceVal 
   */
  replace: function(regex, replaceVal) {
    var currentContent = this.replaceBackup = this.textarea.text()
    this.textarea.val(currentContent.replace(regex, replaceVal))
  },

  undo: function() {
    if (this.replaceBackup === null) return false
    this.textarea.text(this.replaceBackup)
    this.replaceBackup = null
  }
}

var addPatternDialogManager = {
  html: ['  <style>',
  '    .quickEdit-replace {',
  '      position: fixed;',
  '      top: 50%;',
  '      left: 50%;',
  '      transform: translate(-50%, -50%);',
  '      width: 350px;',
  '      border: 1px #ccc solid;',
  '      box-shadow: 0 0 3px #ccc;',
  '      padding: 5px;',
  '      z-index: 10000;',
  '      background-color: white;',
  '    }',
  '    #quickEdit-replace__hideBtn {',
  '      position: absolute;',
  '      top: 5px;',
  '      right: 5px;',
  '      font-size: 26px;',
  '      font-weight: bold;',
  '      cursor: pointer;',
  '    }',
  '    .quickEdit-replace h4 {',
  '      border-bottom: 2px #ccc solid;',
  '      padding-bottom: 5px;',
  '      margin: 5px;',
  '      padding-top: 0;',
  '    }',
  '    .quickEdit-replace main {',
  '      padding: 5px;',
  '      box-sizing: border-box;',
  '    }',
  '    .quickEdit-replace__formItem {',
  '      margin-top: 5px;',
  '      text-align: center;',
  '    }',
  '    .quickEdit-replace__formItem:first-child {',
  '      margin-top: 0;',
  '    }',
  '    .quickEdit-replace__formItem input[type="text"] {',
  '      width: 220px;',
  '      height: 22px;',
  '      text-indent: 5px;',
  '      border: 1px #ABABAB solid;',
  '    }',
  '    .quickEdit-replace footer {',
  '      display: flex;',
  '      justify-content: space-between;',
  '      margin-top: 10px;',
  '    }',
  '    .quickEdit-replace__buttons {',
  '      display: flex;',
  '    }',
  '    .quickEdit-replace__buttons button {',
  '      margin: 0 2px;',
  '    }',
  '    .quickEdit-replace__replaceButtonContainer {',
  '      display: flex;',
  '    }',
  '    .quickEdit-replace__editPattern {',
  '      border-left:1px #ccc solid;',
  '      margin: 0 5px;',
  '      display: inline-block;',
  '    }',
  '    .quickEdit-replace__replaceBtn {',
  '      position: relative',
  '    }',
  '    .quickEdit-replace__replaceBtn > .quickEdit-replace__removePattern {',
  '      display: none',
  '    }',
  '    .quickEdit-replace__replaceBtn:hover .quickEdit-replace__removePattern {',
  '      display: block',
  '    }',
  '    .quickEdit-replace__removePattern {',
  '      width: 12px;',
  '      height: 12px;',
  '      border-radius: 50%;',
  '      background-color: #ccc;',
  '      position: absolute;',
  '      top:0;',
  '      right:0;',
  '      transform: translate(50%, -50%);',
  '    }',
  '  </style>',
  '  <div class="quickEdit-replace" style="display:none">',
  '    <div id="quickEdit-replace__hideBtn">×</div>',
  '    <h4>添加替换规则</h4>',
  '    <main>',
  '      <div class="quickEdit-replace__formItem">',
  '        <label>',
  '          <span>名称:</span>',
  '          <input type="text" name="name">',
  '        </label>',
  '      </div>',
  '      ',
  '      <div class="quickEdit-replace__formItem">',
  '        <label>',
  '          <span>摘要:</span>',
  '          <input type="text" name="summary" placeholder="鼠标置于按钮上时显示,可以留空">',
  '        </label>',
  '      </div>',
  '      <div class="quickEdit-replace__formItem">',
  '        <label>',
  '          <span>查找:</span>',
  '          <input type="text" name="pattern">',
  '        </label>',
  '      </div>',
  '      <div class="quickEdit-replace__formItem">',
  '        <label>',
  '          <span>替换:</span>',
  '          <input type="text" name="replaceVal">',
  '        </label>',
  '      </div>',
  '      <footer>',
  '        <label>',
  '          <span>正则模式</span>',
  '          <input type="checkbox" id="quickEdit-replace__useRegex" style="vertical-align: middle;">',
  '        </label>',
  '        <div class="quickEdit-replace__buttons">',
  '          <button id="quickEdit-replace__addPatternBtn">添加</button>',
  '          <button id="quickEdit-replace__testBtn">测试</button>',
  '          <button id="quickEdit-replace__undoBtn">撤销</button>',
  '        </div>',
  '      </footer>',
  '    </main>',
  '  </div>'].join(''),
  instance: null,

  init: function() {
    $(document.body).append(this.html)
    renderButtons()

    this.instance = $('.quickEdit-replace').eq(0)

    var nameInput = $('.quickEdit-replace__formItem input[name="name"]').eq(0)
    var summaryInput = $('.quickEdit-replace__formItem input[name="summary"]').eq(0)
    var patternInput = $('.quickEdit-replace__formItem input[name="pattern"]').eq(0)
    var replaceValInput = $('.quickEdit-replace__formItem input[name="replaceVal"]').eq(0)

    var useRegexCheckbox = $('#quickEdit-replace__useRegex')
    var hideBtn = $('#quickEdit-replace__hideBtn')
    var addBtn = $('#quickEdit-replace__addPatternBtn')
    var testBtn = $('#quickEdit-replace__testBtn')
    var undoBtn = $('#quickEdit-replace__undoBtn')

    var _this = this
    hideBtn.click(function() {
      _this.instance.hide()
    })

    addBtn.click(function(e) {
      var name = nameInput.val().trim()
      var summary = summaryInput.val().trim()
      var pattern = patternInput.val()
      var replaceVal = replaceValInput.val()
      var useRegex = useRegexCheckbox.prop('checked')

      if (name === '') return mw.notify('名称不能为空', { type: 'warn' })
      if (pattern === '') return mw.notify('查找不能为空', { type: 'warn' })

      var addedResult = patternManager.add({
        name: name,
        summary: summary,
        pattern: pattern,
        replaceVal: replaceVal,
        useRegex: useRegex
      })
      
      if (addedResult) {
        renderButtons()
        mw.notify(addedResult === 1 ? '添加成功' : '修改成功')
      } else {
        mw.notify('输入的正则有误!', { type: 'error' })
      }

    })

    testBtn.click(function(e) {
      var pattern = patternInput.val()
      var replaceVal = replaceValInput.val()
      console.log(useRegexCheckbox)
      var useRegex = useRegexCheckbox.prop('checked')
      
      if (pattern === '') return mw.notify('查找条件不能为空')
      
      console.log(pattern, replaceVal, useRegex)
      try {
        useRegex && new RegExp(pattern, 'g')
      } catch(e) {
        return mw.notify('正则表达式有误!')
      }

      if (!useRegex) {
        pattern = pattern.replace(/([\\\(\)\[\]\{\}\+\.\*\^\$\!\?\|])/g,'\\$1')
      }

      editorManager.replace(new RegExp(pattern, 'g'), replaceVal)
    })

    undoBtn.click(function(e) {
      editorManager.undo()
    })
  },

  hide: function() {
    this.instance.hide()
  },

  /**
   * @param {Object} [options] 如果传options,代表是编辑(将options中的数据填到表单里)
   * @param {string} options.name
   * @param {string} options.pattern
   * @param {string} options.replaceVal
   * @param {boolean} options.useRegex
   * @param {string} [options.summary = ''] 
   */
  show: function(options) {
    if (options) {
      var nameInput = $('.quickEdit-replace__formItem input[name="name"]').eq(0)
      var summaryInput = $('.quickEdit-replace__formItem input[name="summary"]').eq(0)
      var patternInput = $('.quickEdit-replace__formItem input[name="pattern"]').eq(0)
      var replaceValInput = $('.quickEdit-replace__formItem input[name="replaceVal"]').eq(0)
      var useRegexCheckbox = $('#quickEdit-replace__useRegex')

      nameInput.val(options.name)
      summaryInput.val(options.summary)
      patternInput.val(options.pattern)
      replaceValInput.val(options.replaceVal)
      useRegexCheckbox.prop('checked', options.useRegex)
    }

    this.instance.show()
  }
}

function checkRequiredApi() {
  if(typeof MutationObserver == 'undefined'){
    mw.notify('你使用的浏览器版本过低或不符合规范,无法使用Wikiplus-replace插件!', { type : 'warn' })
    return false
  } else {
    return true
  }
}

function injectOpenDialogButton() {
  var openDialogButton = $('<div class="Wikiplus-Btn quickEdit-replace__openDialog">✚</div>')
    .click(function() {
      addPatternDialogManager.show()
    })

  $('.Wikiplus-InterBox-Content > div:first > #Wikiplus-Quickedit-Jump').after(openDialogButton)
  $('.quickEdit-replace__openDialog').after('<div class="quickEdit-replace__replaceButtonContainer">')  // 替换按钮容器
}

// 因为如果正在显示quickEdit的窗口,再次点击快速编辑不会重新创建dom,这个函数将所有快速编辑按钮在打开quickEdit前销毁页面上的已有的quickEdit
function rebindEventForOpenQuickEditBtn() {
	var topBtn = document.getElementById('Wikiplus-Edit-TopBtn')
	topBtn && topBtn.addEventListener('click', function(e){
		if($('.Wikiplus-InterBox').length == 1){
      $('.Wikiplus-InterBox').remove()
		}
  }, true)
  
  $.each(document.getElementsByClassName('mw-editsection'), function(index, value){
    value.addEventListener('click', function(e){
      if(e.target.classList.contains('Wikiplus-Edit-SectionBtn') && $('.Wikiplus-InterBox').length == 1){
      $('.Wikiplus-InterBox').remove()
      }
    }, true)
  })
}

function observerCb(record) {
  var quickEdit = null
  var quickEditTextarea = $('#Wikiplus-Quickedit')

  $.each(record[0].addedNodes, function(item, element){
    if(element.classList && element.classList.contains('Wikiplus-InterBox')){
      quickEdit = element
    }
  })

  if (quickEdit === null) { return }
  
  editorManager.textarea = quickEditTextarea
  injectOpenDialogButton()
}

function main() {
  if (checkRequiredApi() === false) {
    alert('你使用的浏览器暂不支持该插件,请更换浏览器或将该插件移除!')
    return
  }
  
  // 初始化dom变化观察者对象,监听Wikiplus-Quickedit的插入
  var observer = new MutationObserver(observerCb)
  observer.observe(document.body, { childList: true })

  addPatternDialogManager.init()
  rebindEventForOpenQuickEditBtn()
}

$(main)