polyfill

Firefox、Opera、Google Chrome向けのpolyfillです。

目前為 2016-08-17 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/17895/142141/polyfill.js

// ==UserScript==
// @name        polyfill
// @description Firefox、Opera、Google Chrome向けのpolyfillです。
// @version     1.5.0
// @license     Mozilla Public License Version 2.0 (MPL 2.0); https://www.mozilla.org/MPL/2.0/
// @compatible  Firefox
// @compatible  Opera
// @compatible  Chrome
// @author      100の人
// @homepage    https://gf.qytechs.cn/scripts/17895
// ==/UserScript==

(function () {
'use strict';

// Polyfill for Firefox, Opera, and Google Chrome
if (!('prepend' in document)) {
	/**
	 * 複数のインターフェースに[Unscopable]拡張属性を伴うメンバーを実装します。
	 * @param {Function[]} interfaces
	 * @param {Object.<Function>} members
	 */
	let implementUnscopableMembers = function (interfaces, members) {
		for (let i_f of interfaces) {
			Object.assign(i_f.prototype, members);
			if (Symbol.unscopables) {
				let object = {};
				for (let memberName of Object.keys(members)) {
					object[memberName] = true;
				}
				if (i_f.prototype[Symbol.unscopables]) {
					Object.assign(i_f.prototype[Symbol.unscopables], object);
				} else {
					i_f.prototype[Symbol.unscopables] = object;
				}
			}
		}
	};

	/**
	 * @see [DOM Standard]{@link https://dom.spec.whatwg.org/#converting-nodes-into-a-node}
	 * @param {(Node|string)[]} nodes
	 * @returns {(Node|DocumentFragment)}
	 */
	let convertNodesIntoNode = function (nodes) {
		for (let i = 0, l = nodes.length; i < l; i++) {
			if (!(nodes[i] instanceof Node)) {
				nodes[i] = new Text(nodes[i]);
			}
		}
		if (nodes.length === 1) {
			return nodes[0];
		}
		let fragment = new DocumentFragment();
		for (let node of nodes) {
			fragment.appendChild(node);
		}
		return fragment;
	};

	// https://dom.spec.whatwg.org/#interface-parentnode
	implementUnscopableMembers([Document, DocumentFragment, Element], {
		/**
		 * Inserts nodes before the first child of node, while replacing strings in nodes with equivalent Text nodes.
		 * @see [DOM Standard]{@link https://dom.spec.whatwg.org/#dom-parentnode-prepend}
		 * @param {...(Node|string)} nodes
		 * @throws {DOMException} Throws a HierarchyRequestError if the constraints of the node tree are violated.
		 */
		prepend(...nodes) {
			this.insertBefore(convertNodesIntoNode(nodes), this.firstChild);
		},
		/**
		 * Inserts nodes after the last child of node, while replacing strings in nodes with equivalent Text nodes.
		 * @see [DOM Standard]{@link https://dom.spec.whatwg.org/#dom-parentnode-append}
		 * @param {...(Node|string)} nodes
		 * @throws {DOMException} Throws a HierarchyRequestError if the constraints of the node tree are violated.
		 */
		append(...nodes) {
			this.appendChild(convertNodesIntoNode(nodes));
		},
	});

	// https://dom.spec.whatwg.org/#interface-childnode
	implementUnscopableMembers([DocumentType, Element, CharacterData], {
		/**
		 * Inserts nodes just before node, while replacing strings in nodes with equivalent Text nodes.
		 * @see [DOM Standard]{@link https://dom.spec.whatwg.org/#dom-childnode-before}
		 * @param {...(Node|string)} nodes
		 * @throws {DOMException} Throws a HierarchyRequestError if the constraints of the node tree are violated.
		 */
		before(...nodes) {
			let parent = this.parentNode;
			if (!parent) {
				return;
			}
			let viablePreviousSibling;
			while ((viablePreviousSibling = this.previousSibling) && nodes.includes(viablePreviousSibling)) {
			}
			parent.insertBefore(
				convertNodesIntoNode(nodes),
				viablePreviousSibling ? viablePreviousSibling.nextSibling : parent.firstChild
			);
		},
		/**
		 * Inserts nodes just after node, while replacing strings in nodes with equivalent Text nodes.
		 * @see [DOM Standard]{@link https://dom.spec.whatwg.org/#dom-childnode-after}
		 * @param {...(Node|string)} nodes
		 * @throws {DOMException} Throws a HierarchyRequestError if the constraints of the node tree are violated.
		 */
		after(...nodes) {
			let parent = this.parentNode;
			if (!parent) {
				return;
			}
			let viableNextSibling;
			while ((viableNextSibling = this.nextSibling) && nodes.includes(viableNextSibling)) {
			}
			parent.insertBefore(convertNodesIntoNode(nodes), viableNextSibling);
		},
		/**
		 * Replaces node with nodes, while replacing strings in nodes with equivalent Text nodes.
		 * @see [DOM Standard]{@link https://dom.spec.whatwg.org/#dom-childnode-replacewith}
		 * @param {...(Node|string)} nodes
		 * @throws {DOMException} Throws a HierarchyRequestError if the constraints of the node tree are violated.
		 */
		replaceWith(...nodes) {
			let parent = this.parentNode;
			if (!parent) {
				return;
			}
			let viableNextSibling;
			while ((viableNextSibling = this.nextSibling) && nodes.includes(viableNextSibling)) {
			}
			let node = convertNodesIntoNode(nodes);
			if (this.parentNode === parent) {
				parent.replaceChild(node, this);
			} else {
				parent.insertBefore(node, viableNextSibling);
			}
		},
	});
}

if (new URLSearchParams('?').has('?')) {
	URLSearchParams = new Proxy(URLSearchParams, {
		construct(URLSearchParams, argumentsList) {
			if (argumentsList.length > 0 && !(argumentsList[0] instanceof URLSearchParams)) {
				argumentsList[0] = String(argumentsList[0]).replace(/^\?/, '');
			}
			return new URLSearchParams(...argumentsList);
		},
	});
}

if (!('createFor' in URL)) {
	/**
	 * 分をミリ秒に変換するときの乗数。
	 * @constant {number}
	 */
	const MINUTES_TO_MILISECONDS = 60 * 1000;

	/**
	 * Blob URL を自動破棄するまでのミリ秒数。
	 * @constant {number}
	 */
	const MAX_LIFETIME = 10 * MINUTES_TO_MILISECONDS;

	/**
	 * Blob URLを生成し、{@link MAX_LIFETIME}ミリ秒後に破棄します。
	 * @see [File API]{@link https://www.w3.org/TR/FileAPI/#dfn-createFor}
	 * @see [Bug 1062917 - Implement URL.createFor]{@link https://bugzilla.mozilla.org/show_bug.cgi?id=1062917}
	 * @see [Issue 608460 - chromium - Consider implementing URL.createFor() - Monorail]{@link https://bugs.chromium.org/p/chromium/issues/detail?id=608460}
	 * @param {Blob} blob
	 * @returns {string} Blob URL。
	 */
	URL.createFor = function (blob) {
		let url = this.createObjectURL(blob);
		window.setTimeout(() => this.revokeObjectURL(url), MAX_LIFETIME);
		return url;
	};
}

// Polyfill for Firefox
// 6.4 Time Zone Names | ECMAScript® 2016 Internationalization API Specification
// http://www.ecma-international.org/ecma-402/3.0/index.html#sec-time-zone-names
// Bug 837961 – Add support for IANA time zone names to internationalization API
// <https://bugzilla.mozilla.org/show_bug.cgi?id=837961>
// メモ:JavaScript で システム時刻から別のタイムゾーンの時刻へ変換 — ねじろぐ @drillbits
// <http://d.hatena.ne.jp/drillbits/20100127/javascript_timezone_system>
try {
	new Intl.DateTimeFormat('ja', {timeZone: 'Asia/Tokyo'});
} catch (exception) {
	/**
	 * 大文字化したタイムゾーン名とタイムゾーンオフセットの組。
	 * @constant {Object.<number>}
	 */
	const TIMEZONE_OFFSETS = {
		'ASIA/TOKYO': -540,
	};

	/**
	 * 分をミリ秒に変換するときの乗数。
	 * @constant {number}
	 */
	const MINUTES_TO_MILLISECONDS = 60 * 1000;

	Date.prototype.toLocaleString = new Proxy(Date.prototype.toLocaleString, {
		apply: function (target, thisArg, argumentsList) {
			if (typeof argumentsList[1] === 'object' && argumentsList[1] !== null) {
				let timeZone = String(argumentsList[1].timeZone).toUpperCase();
				if (TIMEZONE_OFFSETS.hasOwnProperty(timeZone)) {
					let timeZoneOffset = TIMEZONE_OFFSETS[timeZone];
					if (thisArg.getTimezoneOffset() === timeZoneOffset) {
						delete argumentsList[1].timeZone;
					} else {
						thisArg = new Date(thisArg.getTime() - timeZoneOffset * MINUTES_TO_MILLISECONDS);
						argumentsList[1].timeZone = 'UTC';
					}
				}
			}
			return target.apply(thisArg, argumentsList);
		},
	});
}

// For Firefox 45 ESR
try {
	new CustomEvent('', {detail: {}});
} catch (exception) {
	CustomEvent = new Proxy(CustomEvent, { construct: function (target, args) {
		if (args.length >= 2
			&& typeof args[1] === 'object' && typeof args[1].detail === 'object' && args[1].detail !== null) {
			args[1].detail = cloneInto(args[1].detail, window, {
				cloneFunctions: true,
				wrapReflectors: true,
			});
		}
		return new target(...args);
	} });
}

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址