- // ==UserScript==
- // @name JMUL
- // @name:zh-CN 自用脚本工具库
- // @namespace https://greasyfork.org/users/34556
- // @version 0.1.2
- // @description utilities for monkey scripts
- // @description:zh-CN 工具库
- // @author jferroal
- // @grant GM_xmlhttpRequest
- // ==/UserScript==
-
- (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
- function selectable(je) {
- je.select = select;
- je.getSelection = getSelection;
- je.copyToClipboard = copyToClipboard;
- return je;
- function select(start, end) {
- if (!je.element.focus) {
- console.error('this element can not be selected.');
- }
- je.element.focus();
- start = !!start ? start : 0;
- end = !!end ? end : -1;
- je.element.setSelectionRange(start, end);
- }
-
- function getSelection(start, end) {
- start = !start ? 0 : start;
- // default will get the selected text
- let result = String.prototype.slice.apply(document.getSelection(), [start, end]);
- // if not selected, get current element's text
- if (!result) {
- this.select(start, end);
- result = String.prototype.slice.apply(document.getSelection(), [start, end === -1 ? end += 1 : end]);
- }
- return result;
- }
-
- function copyToClipboard(start, end) {
- start = !start ? 0 : start;
- document.getSelection().removeAllRanges();
- const range = document.createRange();
- range.setStart(je.element, start);
- range.setEnd(je.element, end);
- range.selectNode(je.element);
- document.getSelection().addRange(range);
- try {
- document.execCommand('copy');
- } catch (err) {
- console.error('Oops, unable to copy');
- }
- document.getSelection().removeAllRanges();
- }
- }
-
- function addParser(request, parser) {
- request.parse = parse;
- request.sendAndParse = function () {
- return request.send().then((responseText) => {
- return parse(responseText);
- });
- };
- return request;
-
- function parse(responseText) {
- return new Promise((resolve) => {
- const result = {};
- for (const key of Object.keys(parser.rules)) {
- result[key] = parser.rules[key](responseText);
- }
- resolve(result);
- });
- }
- }
-
- module.exports = {
- selectable: selectable,
- addParser: addParser,
- };
- },{}],2:[function(require,module,exports){
- function toArray(s) {
- return Array.from(s, (v) => v);
- }
-
- class JMElement {
- constructor(tagOrElement) {
- this.element = tagOrElement;
- if (typeof tagOrElement === 'string') {
- this.element = document.createElement(tagOrElement);
- }
- }
-
- setAttribute(attrName, value) {
- this.element.setAttribute(attrName, value);
- }
-
- getAttribute(attrName) {
- return this.element.getAttribute(attrName);
- }
-
- setStyle(styleName, value) {
- this.element.style[styleName] = value;
- }
-
- setCss(styles) {
- if (!styles) return;
- for (const styleName in styles) {
- if (!styles.hasOwnProperty(styleName)) return;
- this.setStyle(styleName, styles[styleName]);
- }
- }
-
- setInnerHTML(value) {
- this.element.innerHTML = value;
- }
- setInnerText(value) {
- this.element.innerText = value;
- }
-
- setId(id) {
- this.setAttribute('id', id);
- }
-
- _setClass(_class) {
- this.setAttribute('class', _class);
- }
-
- addClass(newClass) {
- const oldClassStr = this.getAttribute('class');
- if (oldClassStr.indexOf(newClass) < 0) {
- this._setClass(oldClassStr + ' ' + newClass);
- }
- return this;
- }
-
- removeClass(className) {
- const oldClassStr = this.getAttribute('class');
- const idx = oldClassStr.indexOf(className);
- if (idx > -1) {
- const tmp = toArray(oldClassStr);
- tmp.splice(idx, className.length);
- this._setClass(tmp.join(''));
- }
- return this;
- }
-
- get innerHTML() {
- return this.element.innerHTML;
- }
-
- get innerText() {
- return this.element.innerText;
- }
-
- setValue(value) {
- this.element.value = value;
- }
-
- position(type) {
- const rect = this.element.getBoundingClientRect();
- switch (type) {
- case 'left-top':
- return {x: rect.left, y: rect.top};
- case 'right-top':
- return {x: rect.right, y: rect.top};
- case 'left-bottom':
- return {x: rect.left, y: rect.bottom};
- case 'right-bottom':
- return {x: rect.right, y: rect.bottom};
- case 'center':
- return {x: rect.left + rect.height / 2, y: rect.top + rect.height / 2};
- }
- }
-
- appendTo(parent) {
- parent.appendChild(this.element);
- }
-
- appendChild(child) {
- this.element.appendChild(child.element || child);
- }
-
- listen(eventName, fn) {
- JMElement.addEvent(this.element, eventName, fn);
- }
-
- toString() {
- return this.element.toString();
- }
-
- valueOf() {
- return this.element;
- }
-
- get value() {
- return this.element.value;
- }
-
- static query(selector, index) {
- const els = document.querySelectorAll(selector);
- if (!els) throw new Error('element not found. ');
- if (index === -1) return els.map((el) => new JMElement(el));
- if (index === undefined) return new JMElement(els[0]);
- if (els.length < index + 1) throw new Error('index element not found. ');
- return new JMElement(els[index]);
- }
-
- static addEvent(element, eventName, fn) {
- element.addEventListener(eventName, fn, false);
- }
-
- static getSelectedPosition(type = 'left-top') {
- const focusNode = document.getSelection().focusNode;
- if (!focusNode) throw new Error('no selection, should not create node');
- const focusParentElement = focusNode.parentElement;
- return (new JMElement(focusParentElement)).position(type);
- }
- }
-
- module.exports = JMElement;
-
-
- },{}],3:[function(require,module,exports){
- (function() {
- window.JMUL = {
- Element: require('./element'),
- Decorator: require('./decorator'),
- Request: require('./request').Request,
- Header: require('./request').Header,
- Parser: require('./parser'),
- UI: require('./ui/main'),
- };
- })();
- },{"./decorator":1,"./element":2,"./parser":4,"./request":5,"./ui/main":7}],4:[function(require,module,exports){
-
- const helper = {
- isEmpty: a => !a || !a.length,
- toArray: s => Array.from(s, (v) => v),
- };
-
- class JMXMLResult {
- constructor(tagName, innerText, matches) {
- this.tagName = tagName;
- this.innerText = innerText;
- this.matches = matches;
- }
- }
-
- class JMParser {
- constructor() {
- this.rules = {};
- this.filters = {};
- }
-
- addRule(key, pattern) {
- const tmp = {
- tagName: '',
- attrName: '',
- attrValue: '',
- prevCh: '',
- filterName: '',
- filterParams: [],
- currentFilterParams: ''
- };
- this.rules[key] = helper.toArray(pattern).reduce((res, ch, idx) => {
- switch (ch) {
- case ' ':
- break;
- case '(':
- tmp.prevCh = ch;
- break;
- case '@':
- if (!tmp.tagName) throw new Error('No tagName. ');
- tmp.prevCh = ch;
- break;
- case ')':
- res = JMParser.generate(tmp.tagName, JMParser.attr(tmp.attrName, tmp.attrValue));
- tmp.prevCh = tmp.tagName = tmp.attrName = tmp.attrValue = '';
- break;
- case '|':
- tmp.prevCh = '|';
- const filter = this.filters[tmp.filterName];
- if (filter) {
- res = filter(res, ...tmp.filterParams);
- }
- tmp.filterName = tmp.currentFilterParams = '';
- tmp.filterParams = [];
- break;
- case ',':
- tmp.prevCh = ',';
- if (tmp.currentFilterParams) {
- tmp.filterParams.push(tmp.currentFilterParams);
- }
- tmp.currentFilterParams = '';
- break;
- default:
- if (tmp.prevCh === '@') {
- tmp.attrName += ch;
- } else if (tmp.prevCh === '(') {
- tmp.attrValue += ch;
- } else if(tmp.prevCh === '|') {
- tmp.filterName += ch;
- } else if (tmp.prevCh === ',') {
- tmp.currentFilterParams += ch;
- } else {
- tmp.tagName += ch;
- }
- break;
- }
- return res;
- }, undefined);
- }
-
- addFilter(name, fn) {
- this.filters[name] = (prevFn, ...params) => {
- return (responseText) => {
- const parseRes = prevFn(responseText);
- return fn(parseRes, ...params);
- }
- }
- }
-
- static generate(tagName, attr) {
- const pattern = JMParser.tag(tagName, attr);
- return (responseText) => {
- const allMatch = responseText.match(pattern);
- if (helper.isEmpty(allMatch)) return {found: false};
- return allMatch.reduce((res, matchItem) => {
- const execRes = pattern.exec(matchItem);
- pattern.lastIndex = 0;
- const matchRes = execRes && execRes.slice(1) || [];
- return res.concat([new JMXMLResult(tagName, matchRes[1], matchRes)]);
- }, []);
- }
- }
-
- static tag(name, attr) {
- return new RegExp(`${name}[\\s\\S]*?${attr}[\\s\\S]*?>([\\s\\S]*?)<\/${name}>`, 'gi');
- }
-
- static attr(name, value) {
- return `${name}="(${value})"`;
- }
- }
-
- module.exports = JMParser;
- },{}],5:[function(require,module,exports){
- GM_xmlhttpRequest = window.GM_xmlhttpRequest;
-
- const FnMethodNameMap = {
- 'abort': 'onabort',
- 'failed': 'onerror',
- 'fail': 'onerror',
- 'error': 'onerror',
- 'loaded': 'onload',
- 'load': 'onload',
- 'success': 'onload',
- 'onload': 'onload',
- 'progress': 'onprogress',
- 'onprogress': 'onprogress',
- 'ready': 'onreadystatechange',
- 'readystatechange': 'onreadystatechange',
- 'onreadystatechange': 'onreadystatechange',
- 'timeout': 'ontimeout',
- 'ontimeout': 'ontimeout',
- };
-
- const MethodNameMap = {
- 'get': 'GET',
- 'Get': 'GET',
- 'GET': 'GET',
- 'post': 'POST',
- 'Post': 'POST',
- 'POST': 'POST',
- 'head': 'HEAD',
- 'Head': 'HEAD',
- 'HEAD': 'HEAD',
- 'delete': 'DELETE',
- 'Delete': 'DELETE',
- 'DELETE': 'DELETE',
- 'patch': 'PATCH',
- 'Patch': 'PATCH',
- 'PATCH': 'PATCH',
- 'put': 'PUT',
- 'Put': 'PUT',
- 'PUT': 'PUT',
- };
-
- class JMRequestHeader {
- constructor(headers) {
- if (headers instanceof JMRequestHeader) {
- headers = headers.value();
- }
- this.headerObj = headers;
- }
-
- option(key, value) {
- this.headerObj[key] = value;
- return this;
- } // chain
- setAccept(value) {
- this._accept = this.headerObj.accept = value;
- return this;
- }
-
- setAcceptCharset(value) {
- this.acceptCharset = this.headerObj['Accept-Charset'] = value;
- return this;
- }
-
- setAcceptEncoding(value) {
- this.acceptEncoding = this.headerObj['Accept-Encoding'] = value;
- return this;
- }
-
- setAge(value) {
- this.age = this.headerObj.age = value;
- return this;
- }
-
- setAuthorization(value) {
- this.authorization = this.headerObj.Authorization = value;
- return this;
- }
-
- setContentEncoding(value) {
- this.contentEncoding = this.headerObj['Content-Encoding'] = value;
- return this;
- }
-
- setContentLength(value) {
- this.contentLength = this.headerObj['Content-Length'] = value;
- return this;
- }
-
- setContentType(value) {
- this.contentType = this.headerObj['Content-Type'] = value;
- return this;
- }
-
- setCookie(value) {
- this.cookie = this.headerObj.Cookie = value;
- return this;
- }
-
- setUA(value) {
- this.ua = this.headerObj['User-Agent'] = value;
- return this;
- }
-
- value() {
- return this.headerObj;
- }
- }
-
- class JMRequest {
- constructor(options) {
- this._method = options.method && MethodNameMap[options.method] || 'GET';
- this._url = options.url || '';
- this.options = {};
- this.options.headers = new JMRequestHeader(options.headers || {});
- for (let key of Object.keys(options)) {
- if (FnMethodNameMap[key] && typeof options[key] === 'function') {
- this.options[FnMethodNameMap[key]] = options[key];
- }
- }
- this.options.data = this.handleRequestData(options.data)
- }
-
- handleRequestData(data) {
- if (!data) return '';
- const contentType = this.options.headers.contentType;
- if (!contentType || contentType === 'application/json') {
- return JMRequest.toJsonData(data);
- } else if (contentType === 'application/x-www-form-urlencoded') {
- return JMRequest.toFormData(data);
- } else {
- // treat other as plain/text, do not support multipart/form-data
- return data.toString();
- }
- }
-
- setMethod(_method) {
- this._method = MethodNameMap[_method];
- return this;
- }
-
- setUrl(_url) {
- this._url = _url;
- return this;
- }
-
- setHeaders(headers) {
- this.options.headers = headers;
- return this;
- }
-
- setData(obj) {
- this.options.data = this.handleRequestData(obj);
- return this;
- }
-
- load(fn) {
- this.options.onload = fn;
- return this;
- }
-
- error(fn) {
- this.options.onerror = fn;
- return this;
- }
-
- timeout(fn) {
- this.options.ontimeout = fn;
- return this;
- }
-
- readyStateChange(fn) {
- this.options.onreadystatechange = fn;
- return this;
- }
-
- abort(fn) {
- this.options.onabort = fn;
- return this;
- }
-
- progress(fn) {
- this.options.onprogress = fn;
- return this;
- }
-
- send() {
- return JMRequest.request(this._method, this._url, this.options);
- }
-
- static toFormData(data) {
- if (typeof data === 'string') {
- return data;
- } else {
- let result = '';
- for (let key of Object.keys(data)) {
- result += key + '=' + data[key] + '&';
- }
- return result.slice(0, -1);
- }
- }
-
- static toJsonData(data) {
- if (typeof data === 'object') {
- return JSON.stringify(data);
- } else {
- return data;
- }
- }
-
- static request(method, url, options) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: MethodNameMap[method],
- url: url,
- headers: options.headers.value(),
- data: options.data,
- onreadystatechange: (response) => {
- if (!options.onreadystatechange) return console.log('on ready state change. ');
- const fn = options.onreadystatechange;
- (!fn.then ? Promise.resolve(fn(response)) : fn(response)).then(function (res) {
- resolve(res);
- });
- },
- onabort: (response) => {
- if (!options.onabort) {
- console.error('on abort. ');
- reject({cause: 'abort'});
- } else {
- const fn = options.onabort;
- (!fn.then ? Promise.resolve(fn(response)) : fn(response)).then(function (res) {
- resolve(res);
- });
- }
-
- },
- onerror: (response) => {
- if (!options.onerror) {
- console.error('on error. ');
- reject({cause: 'error', response: response});
- } else {
- const fn = options.onerror;
- (!fn.then ? Promise.resolve(fn(response)) : fn(response)).then(function (res) {
- resolve(res);
- });
- }
- },
- onprogress: (response) => {
- if (!options.onprogress) return console.log('on progress. ');
- const fn = options.onprogress;
- (!fn.then ? Promise.resolve(fn(response)) : fn(response)).then(function (res) {
- resolve(res);
- });
- }
- ,
- ontimeout: (response) => {
- if (!options.ontimeout) {
- console.error('on timeout. ');
- reject({cause: 'timeout', response: response});
- }
- const fn = options.ontimeout;
- (!fn.then ? Promise.resolve(fn(response)) : fn(response)).then(function (res) {
- resolve(res);
- });
- },
- onload: (response) => {
- if (!options.onload) {
- console.log('on load. ');
- resolve(response);
- } else {
- const fn = options.onload;
- (!fn.then ? Promise.resolve(fn(response)) : fn(response)).then(function (res) {
- resolve(res);
- });
- }
- },
- })
- });
- }
-
- static get(url, options) {
- return JMRequest.request('GET', url, options);
- }
-
- static post(url, options) {
- return JMRequest.request('POST', url, options);
- }
-
- static put(url, options) {
- return JMRequest.request('PUT', url, options);
- }
-
- static delete(url, options) {
- return JMRequest.request('DELETE', url, options);
- }
-
- static head(url, options) {
- return JMRequest.request('HEAD', url, options);
- }
-
- static patch(url, options) {
- return JMRequest.request('PATCH', url, options);
- }
- }
-
- module.exports = {
- Request: JMRequest,
- Header: JMRequestHeader,
- };
- },{}],6:[function(require,module,exports){
- const JMElement = require('../element');
-
- class BaseButton extends JMElement {
- constructor() {
- super('button');
- this.btnClickedStyleChangeTimeout = undefined;
- }
-
- setNormalBtnBoxShadow() {
- this.setStyle('boxShadow', '0 0 2px 2px rgba(0, 0, 0, 0.08)');
- }
-
- setClickedBtnBoxShadow() {
- this.setStyle('boxShadow', 'none');
- }
-
- listenClick(fn) {
- this.listen('click', (e) => {
- this.setClickedBtnBoxShadow();
- if (this.btnClickedStyleChangeTimeout) {
- clearTimeout(this.btnClickedStyleChangeTimeout);
- this.btnClickedStyleChangeTimeout = null;
- }
- this.btnClickedStyleChangeTimeout = setTimeout(() => {
- this.setNormalBtnBoxShadow();
- }, 100);
- fn(e, this);
- })
- }
- }
- class IconButton {
- constructor(icon, size, clickFn) {
- this.button = new BaseButton();
- IconButton.initBtnStyle(this.button, typeof size === 'string' ? '128px' : size + 'px');
- this.image = new JMElement('img');
- this.image.setAttribute('src', icon);
- IconButton.initImageStyle(this.image);
- this.button.appendChild(this.image);
- this.button.listenClick(clickFn)
- }
-
- appendTo(parent) {
- this.button.appendTo(parent);
- }
-
- get element() {
- return this.button;
- }
-
- static initBtnStyle(button, size) {
- button.setCss({
- position: 'relative',
- height: size,
- width: size,
- padding: '0',
- borderRadius: '50%',
- border: 'none',
- outline: 'none',
- });
- }
-
- static initImageStyle(image) {
- image.setCss({
- width: '100%',
- height: '100%',
- borderRadius: '50%',
- cursor: 'pointer'
- })
- }
- }
-
- class NormalButton {
- constructor(label, size, clickFn) {
- this.button = new BaseButton();
- NormalButton.initBtnStyle(this.button, NormalButton._handleSizeParam(size));
- this.label = new JMElement('p');
- NormalButton.initLabelStyle(this.label);
- this.label.innerText(label);
- this.button.appendChild(this.label);
- this.button.listenClick(clickFn)
- }
-
- appendTo(parent) {
- this.button.appendTo(parent);
- }
-
- get element() {
- return this.button;
- }
-
- static initBtnStyle(button, size) {
- button.setCss({
- height: size.height || '24px',
- width: '64px',
- borderRadius: '4px',
- border: 'none',
- backgroundColor: 'skyblue',
- cursor: 'pointer',
- outline: 'none',
- });
- }
-
- static initLabelStyle(label) {
- label.setCss({
- fontSize: '12px',
- color: 'rgba(255, 255,255, 0.87)',
- lineHeight: '100%',
- margin: '0',
- });
- }
-
- static _handleSizeParam(size) {
- switch (typeof size) {
- case 'object':
- return {
- height: typeof size.height === 'string' ? size.height : size.height + 'px',
- width: typeof size.width === 'string' ? size.width : size.width + 'px',
- };
- case 'string':
- return {height: size, width: size};
- case 'number':
- return {height: size + 'px', width: size + 'px'};
- }
- }
- }
-
- class JMButtonFactory {
- constructor() {
- if (!JMButtonFactory.ButtonFactory) {
- JMButtonFactory.ButtonFactory = this;
- }
- return JMButtonFactory.ButtonFactory;
- }
-
- static create(type, iconOrLabel, size, clickFn) {
- switch (type) {
- case 'icon':
- return new IconButton(iconOrLabel, size, clickFn);
- case 'normal':
- default:
- return new NormalButton(iconOrLabel, size, clickFn);
- }
- }
- }
- JMButtonFactory.ButtonFactory = null;
-
- module.exports = JMButtonFactory;
-
- },{"../element":2}],7:[function(require,module,exports){
- module.exports = {
- Button: require('./button')
- }
- },{"./button":6}]},{},[3]);