// ==UserScript==
// @name fill the input and select of form as last time inputed automatically
// @name:zh-CN 使用上次输入的值自动填写表格
// @namespace http://tampermonkey.net/
// @description This script supports SPA like vue。
// @description:zh-CN 对所有网站生效,支持SPA(比如vue)动态插入的input和select。比如可以自动填写用户名和密码,自动点击同意协议。浏览器需要安装Tampermonkey或者Greasemonkey扩展,安卓手机浏览器推荐Yandex或者Kiwi浏览器。
// @include http://*
// @include https://*
// @exclude https://www.baidu.com/*
// @exclude https://www.google.com*
// @grant GM_setValue
// @grant GM_getValue
// @author yechenyin
// @license MIT
// @version 1.0.3
// ==/UserScript==
//闭包里的方法的用法和jquery同命名方法一致
(function () {
var jQuery = function (selector) {
return new jQuery.fn.init(selector)
}
jQuery.fn = jQuery.prototype = {
length: 0,
selector: '',
init: function (elementOrSelector) {
var nodes = []
if (typeof (elementOrSelector) == 'string') {
this.selector = elementOrSelector
nodes = document.querySelectorAll(this.selector)
} else if (elementOrSelector instanceof NodeList) {
nodes = elementOrSelector
} else if (elementOrSelector instanceof Element) {
nodes = [elementOrSelector]
}
this.length = nodes.length
for (var i = 0; i < nodes.length; i++) {
this[i] = nodes[i]
}
},
each: function (callback) {
for (var i = 0; i < this.length; i++) {
callback.call(this[i])
}
},
on: function (event, callback) {
this.each(function () {
this.addEventListener(event, callback)
})
},
text: function (string) {
var i = 0
if (string !== undefined) {
for (i = 0; i < this.length; i++) {
this[i].innerText = string
}
} else {
return this[0].innerText
}
},
val: function (value) {
if (value === undefined) {
var ret
if (this[0].type == 'checkbox')
ret = this[0].checked
else if (this[0].type == 'radio' || this[0].type == 'text' || this[0].type == 'password' || this[0].tagName == 'select')
ret = this[0].value
return ret
} else {
for (var i = 0; i < this.length; i++) {
if (this[i].type == 'checkbox' && Boolean(value))
this[i].click()
else if (this[i].type == 'radio')
this[i].checked = this[i].value == value
else if (this[i].type == 'text')
this[i].value = value
else if (this[i].type == 'password')
this[i].value = value
else if (this[i].tagName == 'select')
this[i].value = value
this[i].dispatchEvent(new Event('input', { bubbles: true }))
}
}
},
attr: function (attribute, value) {
if (value === undefined) {
return this[0].getAttribute(attribute)
} else {
this.each(function () {
this.setAttribute(attribute, value)
})
}
},
click: function () {
this[0].click()
},
find: function (selector) {
var j = 0
var result = []
for (var i = 0; i < this.length; i++) {
if (this[i].querySelectorAll(selector).length) {
}
}
},
append: function (html) {
for (var i = 0; i < this.length; i++) {
this[i].innerHTML += html
}
},
}
jQuery.fn.init.prototype = jQuery.fn
if (!window.jQuery) window.jQuery = window.$ = jQuery
})()
//每当符合选择器规则的元素插入到页面中时,唤起callback方法。如果trigger_once为true,只唤起一次
jQuery.fn.inserted = function (callback, trigger_once = false) {
var selector = this.selector;
if ($(selector).length > 0) {
//log($(selector).length + ' ' + selector + " is loaded at begin");
callback.call($(selector));
}
var finished = false
var recall = function (mutationsList, observer) {
for (var i = 0; i < mutationsList.length; i++) {
//log(mutationsList[i].target)
if (mutationsList[i].addedNodes) {
for (var j = 0; j < mutationsList[i].addedNodes.length; j++) {
var element = mutationsList[i].addedNodes[j]
if (!(trigger_once && finished) && element instanceof Element && element.querySelectorAll(selector).length) {
var container = ''
if (element.id)
container = '#' + element.id
else if (element.className)
container = '.' + element.className
else
container = element.outerHtml
//log(container + ' which contains ' + selector + ' is loaded')
if (trigger_once) {
observer.disconnect()
finished = true
}
callback.call($(element.querySelectorAll(selector)))
}
}
}
}
};
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
if (MutationObserver) {
var observer = new MutationObserver(recall)
observer.observe(document.body, {
childList: true,
subtree: true
})
}
}
//当符合选择器规则的元素插入到页面中时,调用一次callback方法,之后不会再唤起
jQuery.fn.loaded = function (callback) {
if (callback)
this.inserted(callback, true);
}
//每当元素类名变化时,唤起callback方法
jQuery.fn.onClassChanged = function (callback) {
var recall = function (mutationsList, observer) {
for (var i = 0; i < mutationsList.length; i++) {
//log(mutationsList[i].target)
if (mutationsList[i].type === 'attributes' && mutationsList[i].attributeName === 'class') {
//callback.call($(mutationsList[i].target))
callback.call(mutationsList[i].target)
}
}
};
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
if (MutationObserver) {
var observer = new MutationObserver(recall)
var list = document.querySelectorAll(this.selector)
for (var i = 0; i < list.length; i++) {
observer.observe(list[i], { attributes: true })
}
}
}
//在元素加载完成后经过delay(单位毫秒)延迟后点击元素
jQuery.fn.clickAfterLoaded = function (delay = 0) {
this.loaded(function () {
setTimeout(function () {
this[0].click()
}.bind(this), delay)
})
}
//在元素加载完成后经过delay(单位毫秒)延迟后设置输入值
jQuery.fn.setAfterLoaded = function (value, delay = 0) {
this.loaded(function () {
setTimeout(function () {
this.val(value)
}.bind(this), delay)
})
}
//替代得到http成功回应后的回调
$.replaceResponseCallback = function (callback, continueOriginalCallback = false) {
var open = XMLHttpRequest.prototype.open
XMLHttpRequest.prototype.open = function () {
this.addEventListener(
'readystatechange',
function () {
if (
this.readyState == 4 &&
this.response
) {
callback.call(this)
}
},
false
)
if (continueOriginalCallback)
open.apply(this, arguments)
XMLHttpRequest.prototype.open = open
}
}
//url改变后唤起callback,支持监测SPA的#后面的字符串变化
$.onUrlChange = function (callback) {
history.pushState = ((f) =>
function pushState() {
var ret = f.apply(this, arguments)
window.dispatchEvent(new Event('pushstate'))
window.dispatchEvent(new Event('urlchange'))
return ret
})(history.pushState)
history.replaceState = ((f) =>
function replaceState() {
var ret = f.apply(this, arguments)
window.dispatchEvent(new Event('replacestate'))
window.dispatchEvent(new Event('urlchange'))
return ret
})(history.replaceState)
window.addEventListener('popstate', () => {
window.dispatchEvent(new Event('urlchange'))
})
window.addEventListener('urlchange', function () {
callback()
})
}
jQuery.fn.saveChangedValue = function () {
var that = this
that.on('change', function () {
//log(that)
var href = 'inputed_' + location.href.replace(/\?.*/, '')
var inputs = ''
if (typeof GM_getValue === 'undefined')
inputs = localStorage[href]
else if (GM_getValue(href)) {
inputs = GM_getValue(href)
}
if (inputs)
inputs = JSON.parse(inputs)
else
inputs = {}
//log(this.constructor.name)
//log(Object.keys(this))
var name = ''
for (var i = 0; i < that.length; i++) {
if (this == that[i])
name = i
}
inputs[name] = $(this).val()
log(name, inputs[name])
if (typeof GM_setValue === 'undefined')
localStorage[href] = JSON.stringify(inputs)
else
GM_setValue(href, JSON.stringify(inputs))
//log(GM_getValue(href))
})
}
jQuery.fn.recoverSavedValue = function () {
this.inserted(function () {
var that = this
var href = 'inputed_' + location.href.replace(/\?.*/, '')
var inputs = ''
if (typeof GM_getValue === 'undefined')
inputs = localStorage[href]
else if (GM_getValue(href)) {
inputs = GM_getValue(href)
}
if (inputs)
inputs = JSON.parse(inputs)
else
inputs = {}
log(inputs)
if (Object.keys(inputs).length) {
this.each(function () {
var name = ''
for (var i = 0; i < that.length; i++) {
if (this == that[i])
name = i
}
log(name)
if (inputs.hasOwnProperty(name)) {
$(this).val(inputs[name])
}
})
}
})
}
function log(info) {
var printInConsole = false;
if (printInConsole) {
console.log(info)
}
}
window.onload = function () {
$('input, select').recoverSavedValue()
$('input, select').inserted(function () {
$('input, select').saveChangedValue()
$('.el-select-dropdown__item').onClassChanged(function () {
if (this.classList.contains('selected')) {
log(this.innerText)
}
})
})
}