From 338f01be0199ee0c229a51996ddfcdcae2de1380 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 2 Apr 2020 22:49:27 +0200 Subject: [PATCH] fixes and library updates --- background.js | 14 +- content.js | 19 +- lib/JSDOMParser.js | 3 +- lib/Readability-readerable.js | 13 +- lib/Readability.js | 192 ++-- lib/browser-polyfill.js | 1658 ++++++++++----------------------- lib/cash.min.js | 71 +- trilium-web-clipper.iml | 4 +- 8 files changed, 669 insertions(+), 1305 deletions(-) diff --git a/background.js b/background.js index 4e323a735..241498c6b 100644 --- a/background.js +++ b/background.js @@ -124,11 +124,15 @@ async function postProcessImage(image) { if (image.src.startsWith("data:image/")) { image.dataUrl = image.src; image.src = "inline." + image.src.substr(11, 3); // this should extract file type - png/jpg - - return; } - - image.dataUrl = await fetchImage(image.src, image); + else { + try { + image.dataUrl = await fetchImage(image.src, image); + } + catch (e) { + console.log(`Cannot fetch image from ${image.src}`); + } + } } async function postProcessImages(resp) { @@ -268,6 +272,8 @@ browser.contextMenus.onClicked.addListener(async function(info, tab) { }); browser.runtime.onMessage.addListener(async request => { + console.log("Received", request); + if (request.name === 'openNoteInTrilium') { const resp = await triliumServerFacade.callService('POST', 'open/' + request.noteId); diff --git a/content.js b/content.js index d4ca967e7..1fb006636 100644 --- a/content.js +++ b/content.js @@ -189,14 +189,21 @@ function getImages(container) { continue; } - const imageId = randomString(20); + const existingImage = images.find(image => image.src === img.src); - images.push({ - imageId: imageId, - src: img.src - }); + if (existingImage) { + img.src = existingImage.imageId; + } + else { + const imageId = randomString(20); - img.src = imageId; + images.push({ + imageId: imageId, + src: img.src + }); + + img.src = imageId; + } } return images; diff --git a/lib/JSDOMParser.js b/lib/JSDOMParser.js index dd7cb3a0a..30c7d4cd9 100644 --- a/lib/JSDOMParser.js +++ b/lib/JSDOMParser.js @@ -1,5 +1,3 @@ -// https://github.com/mozilla/readability/tree/814f0a3884350b6f1adfdebb79ca3599e9806605 - /*eslint-env es6:false*/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, @@ -310,6 +308,7 @@ } } getElems(this); + elems._isLiveNodeList = true; return elems; } diff --git a/lib/Readability-readerable.js b/lib/Readability-readerable.js index 1be7c73fb..73060fc05 100644 --- a/lib/Readability-readerable.js +++ b/lib/Readability-readerable.js @@ -1,5 +1,3 @@ -// https://github.com/mozilla/readability/tree/814f0a3884350b6f1adfdebb79ca3599e9806605 - /* eslint-env es6:false */ /* globals exports */ /* @@ -26,13 +24,16 @@ var REGEXPS = { // NOTE: These two regular expressions are duplicated in // Readability.js. Please keep both copies in sync. - unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i, - okMaybeItsACandidate: /and|article|body|column|main|shadow/i, + unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i, + okMaybeItsACandidate: /and|article|body|column|content|main|shadow/i, }; function isNodeVisible(node) { - // Have to null-check node.style to deal with SVG and MathML nodes. - return (!node.style || node.style.display != "none") && !node.hasAttribute("hidden"); + // Have to null-check node.style and node.className.indexOf to deal with SVG and MathML nodes. + return (!node.style || node.style.display != "none") + && !node.hasAttribute("hidden") + //check for "fallback-image" so that wikimedia math images are displayed + && (!node.hasAttribute("aria-hidden") || node.getAttribute("aria-hidden") != "true" || (node.className && node.className.indexOf && node.className.indexOf("fallback-image") !== -1)); } /** diff --git a/lib/Readability.js b/lib/Readability.js index a35703b68..aa9167836 100644 --- a/lib/Readability.js +++ b/lib/Readability.js @@ -1,5 +1,3 @@ -// https://github.com/mozilla/readability/tree/814f0a3884350b6f1adfdebb79ca3599e9806605 - /*eslint-env es6:false*/ /* * Copyright (c) 2010 Arc90 Inc @@ -38,6 +36,7 @@ function Readability(doc, options) { options = options || {}; this._doc = doc; + this._docJSDOMParser = this._doc.firstChild.__JSDOMParser__; this._articleTitle = null; this._articleByline = null; this._articleDir = null; @@ -50,11 +49,12 @@ function Readability(doc, options) { this._nbTopCandidates = options.nbTopCandidates || this.DEFAULT_N_TOP_CANDIDATES; this._charThreshold = options.charThreshold || this.DEFAULT_CHAR_THRESHOLD; this._classesToPreserve = this.CLASSES_TO_PRESERVE.concat(options.classesToPreserve || []); + this._keepClasses = !!options.keepClasses; // Start with all flags set this._flags = this.FLAG_STRIP_UNLIKELYS | - this.FLAG_WEIGHT_CLASSES | - this.FLAG_CLEAN_CONDITIONALLY; + this.FLAG_WEIGHT_CLASSES | + this.FLAG_CLEAN_CONDITIONALLY; var logEl; @@ -116,8 +116,8 @@ Readability.prototype = { REGEXPS: { // NOTE: These two regular expressions are duplicated in // Readability-readerable.js. Please keep both copies in sync. - unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i, - okMaybeItsACandidate: /and|article|body|column|main|shadow/i, + unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i, + okMaybeItsACandidate: /and|article|body|column|content|main|shadow/i, positive: /article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i, negative: /hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i, @@ -126,6 +126,7 @@ Readability.prototype = { replaceFonts: /<(\/?)font[^>]*>/gi, normalize: /\s{2,}/g, videos: /\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i, + shareElements: /(\b|_)(share|sharedaddy)(\b|_)/i, nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i, prevLink: /(prev|earl|old|new|<|«)/i, whitespace: /^\s*$/, @@ -159,13 +160,15 @@ Readability.prototype = { * * @param Element * @return void - **/ + **/ _postProcessContent: function(articleContent) { // Readability cannot open relative uris so we convert them to absolute uris. this._fixRelativeUris(articleContent); - // Remove classes. - this._cleanClasses(articleContent); + if (!this._keepClasses) { + // Remove classes. + this._cleanClasses(articleContent); + } }, /** @@ -179,6 +182,10 @@ Readability.prototype = { * @return void */ _removeNodes: function(nodeList, filterFn) { + // Avoid ever operating on live node lists. + if (this._docJSDOMParser && nodeList._isLiveNodeList) { + throw new Error("Do not pass live node lists to _removeNodes"); + } for (var i = nodeList.length - 1; i >= 0; i--) { var node = nodeList[i]; var parentNode = node.parentNode; @@ -198,6 +205,10 @@ Readability.prototype = { * @return void */ _replaceNodeTags: function(nodeList, newTagName) { + // Avoid ever operating on live node lists. + if (this._docJSDOMParser && nodeList._isLiveNodeList) { + throw new Error("Do not pass live node lists to _replaceNodeTags"); + } for (var i = nodeList.length - 1; i >= 0; i--) { var node = nodeList[i]; this._setNodeTag(node, newTagName); @@ -285,11 +296,11 @@ Readability.prototype = { _cleanClasses: function(node) { var classesToPreserve = this._classesToPreserve; var className = (node.getAttribute("class") || "") - .split(/\s+/) - .filter(function(cls) { - return classesToPreserve.indexOf(cls) != -1; - }) - .join(" "); + .split(/\s+/) + .filter(function(cls) { + return classesToPreserve.indexOf(cls) != -1; + }) + .join(" "); if (className) { node.setAttribute("class", className); @@ -330,11 +341,21 @@ Readability.prototype = { this._forEachNode(links, function(link) { var href = link.getAttribute("href"); if (href) { - // Replace links with javascript: URIs with text content, since + // Remove links with javascript: URIs, since // they won't work after scripts have been removed from the page. if (href.indexOf("javascript:") === 0) { - var text = this._doc.createTextNode(link.textContent); - link.parentNode.replaceChild(text, link); + // if the link only contains simple text content, it can be converted to a text node + if (link.childNodes.length === 1 && link.childNodes[0].nodeType === this.TEXT_NODE) { + var text = this._doc.createTextNode(link.textContent); + link.parentNode.replaceChild(text, link); + } else { + // if the link has multiple children, they should all be preserved + var container = this._doc.createElement("span"); + while (link.childNodes.length > 0) { + container.appendChild(link.childNodes[0]); + } + link.parentNode.replaceChild(container, link); + } } else { link.setAttribute("href", toAbsoluteURI(href)); } @@ -386,8 +407,8 @@ Readability.prototype = { // Check if we have an heading containing this exact string, so we // could assume it's the full title. var headings = this._concatNodeLists( - doc.getElementsByTagName("h1"), - doc.getElementsByTagName("h2") + doc.getElementsByTagName("h1"), + doc.getElementsByTagName("h2") ); var trimmedTitle = curTitle.trim(); var match = this._someNode(headings, function(heading) { @@ -422,7 +443,7 @@ Readability.prototype = { var curTitleWordCount = wordCount(curTitle); if (curTitleWordCount <= 4 && (!titleHadHierarchicalSeparators || - curTitleWordCount != wordCount(origTitle.replace(/[\|\-\\\/>»]+/g, "")) - 1)) { + curTitleWordCount != wordCount(origTitle.replace(/[\|\-\\\/>»]+/g, "")) - 1)) { curTitle = origTitle; } @@ -439,13 +460,13 @@ Readability.prototype = { var doc = this._doc; // Remove all style tags in head - this._removeNodes(doc.getElementsByTagName("style")); + this._removeNodes(this._getAllNodesWithTag(doc, ["style"])); if (doc.body) { this._replaceBrs(doc.body); } - this._replaceNodeTags(doc.getElementsByTagName("font"), "SPAN"); + this._replaceNodeTags(this._getAllNodesWithTag(doc, ["font"]), "SPAN"); }, /** @@ -456,8 +477,8 @@ Readability.prototype = { _nextElement: function (node) { var next = node; while (next - && (next.nodeType != this.ELEMENT_NODE) - && this.REGEXPS.whitespace.test(next.textContent)) { + && (next.nodeType != this.ELEMENT_NODE) + && this.REGEXPS.whitespace.test(next.textContent)) { next = next.nextSibling; } return next; @@ -525,7 +546,7 @@ Readability.prototype = { _setNodeTag: function (node, tag) { this.log("_setNodeTag", node, tag); - if (node.__JSDOMParser__) { + if (this._docJSDOMParser) { node.localName = tag.toLowerCase(); node.tagName = tag.toUpperCase(); return node; @@ -588,7 +609,7 @@ Readability.prototype = { this._forEachNode(articleContent.children, function (topCandidate) { this._cleanMatchedNodes(topCandidate, function (node, matchString) { - return /share/.test(matchString) && node.textContent.length < shareElementThreshold; + return this.REGEXPS.shareElements.test(matchString) && node.textContent.length < shareElementThreshold; }); }); @@ -625,7 +646,7 @@ Readability.prototype = { this._cleanConditionally(articleContent, "div"); // Remove extra paragraphs - this._removeNodes(articleContent.getElementsByTagName("p"), function (paragraph) { + this._removeNodes(this._getAllNodesWithTag(articleContent, ["p"]), function (paragraph) { var imgCount = paragraph.getElementsByTagName("img").length; var embedCount = paragraph.getElementsByTagName("embed").length; var objectCount = paragraph.getElementsByTagName("object").length; @@ -662,7 +683,7 @@ Readability.prototype = { * * @param Element * @return void - **/ + **/ _initializeNode: function(node) { node.readability = {"contentScore": 0}; @@ -769,7 +790,7 @@ Readability.prototype = { * * @param page a document to run upon. Needs to be a full document, complete with body. * @return Element - **/ + **/ _grabArticle: function (page) { this.log("**** grabArticle ****"); var doc = this._doc; @@ -823,8 +844,8 @@ Readability.prototype = { // Remove DIV, SECTION, and HEADER nodes without any content(e.g. text, image, video, or iframe). if ((node.tagName === "DIV" || node.tagName === "SECTION" || node.tagName === "HEADER" || - node.tagName === "H1" || node.tagName === "H2" || node.tagName === "H3" || - node.tagName === "H4" || node.tagName === "H5" || node.tagName === "H6") && + node.tagName === "H1" || node.tagName === "H2" || node.tagName === "H3" || + node.tagName === "H4" || node.tagName === "H5" || node.tagName === "H6") && this._isElementWithoutContent(node)) { node = this._removeAndGetNext(node); continue; @@ -880,7 +901,7 @@ Readability.prototype = { * Then add their score to their parent node. * * A score is determined by things like number of commas, class names, etc. Maybe eventually link density. - **/ + **/ var candidates = []; this._forEachNode(elementsToScore, function(elementToScore) { if (!elementToScore.parentNode || typeof(elementToScore.parentNode.tagName) === "undefined") @@ -1085,7 +1106,7 @@ Readability.prototype = { if (nodeLength > 80 && linkDensity < 0.25) { append = true; } else if (nodeLength < 80 && nodeLength > 0 && linkDensity === 0 && - nodeContent.search(/\.( |$)/) !== -1) { + nodeContent.search(/\.( |$)/) !== -1) { append = true; } } @@ -1264,12 +1285,12 @@ Readability.prototype = { // get title metadata.title = values["dc:title"] || - values["dcterm:title"] || - values["og:title"] || - values["weibo:article:title"] || - values["weibo:webpage:title"] || - values["title"] || - values["twitter:title"]; + values["dcterm:title"] || + values["og:title"] || + values["weibo:article:title"] || + values["weibo:webpage:title"] || + values["title"] || + values["twitter:title"]; if (!metadata.title) { metadata.title = this._getArticleTitle(); @@ -1277,17 +1298,17 @@ Readability.prototype = { // get author metadata.byline = values["dc:creator"] || - values["dcterm:creator"] || - values["author"]; + values["dcterm:creator"] || + values["author"]; // get description metadata.excerpt = values["dc:description"] || - values["dcterm:description"] || - values["og:description"] || - values["weibo:article:description"] || - values["weibo:webpage:description"] || - values["description"] || - values["twitter:description"]; + values["dcterm:description"] || + values["og:description"] || + values["weibo:article:description"] || + values["weibo:webpage:description"] || + values["description"] || + values["twitter:description"]; // get site name metadata.siteName = values["og:site_name"]; @@ -1299,14 +1320,14 @@ Readability.prototype = { * Removes script tags from the document. * * @param Element - **/ + **/ _removeScripts: function(doc) { - this._removeNodes(doc.getElementsByTagName("script"), function(scriptNode) { + this._removeNodes(this._getAllNodesWithTag(doc, ["script"]), function(scriptNode) { scriptNode.nodeValue = ""; scriptNode.removeAttribute("src"); return true; }); - this._removeNodes(doc.getElementsByTagName("noscript")); + this._removeNodes(this._getAllNodesWithTag(doc, ["noscript"])); }, /** @@ -1316,7 +1337,7 @@ Readability.prototype = { * * @param Element * @param string tag of child element - **/ + **/ _hasSingleTagInsideElement: function(element, tag) { // There should be exactly 1 element child with given tag if (element.children.length != 1 || element.children[0].tagName !== tag) { @@ -1326,15 +1347,15 @@ Readability.prototype = { // And there should be no text nodes with real content return !this._someNode(element.childNodes, function(node) { return node.nodeType === this.TEXT_NODE && - this.REGEXPS.hasContent.test(node.textContent); + this.REGEXPS.hasContent.test(node.textContent); }); }, _isElementWithoutContent: function(node) { return node.nodeType === this.ELEMENT_NODE && - node.textContent.trim().length == 0 && - (node.children.length == 0 || - node.children.length == node.getElementsByTagName("br").length + node.getElementsByTagName("hr").length); + node.textContent.trim().length == 0 && + (node.children.length == 0 || + node.children.length == node.getElementsByTagName("br").length + node.getElementsByTagName("hr").length); }, /** @@ -1345,23 +1366,23 @@ Readability.prototype = { _hasChildBlockElement: function (element) { return this._someNode(element.childNodes, function(node) { return this.DIV_TO_P_ELEMS.indexOf(node.tagName) !== -1 || - this._hasChildBlockElement(node); + this._hasChildBlockElement(node); }); }, /*** * Determine if a node qualifies as phrasing content. * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Phrasing_content - **/ + **/ _isPhrasingContent: function(node) { return node.nodeType === this.TEXT_NODE || this.PHRASING_ELEMS.indexOf(node.tagName) !== -1 || - ((node.tagName === "A" || node.tagName === "DEL" || node.tagName === "INS") && - this._everyNode(node.childNodes, this._isPhrasingContent)); + ((node.tagName === "A" || node.tagName === "DEL" || node.tagName === "INS") && + this._everyNode(node.childNodes, this._isPhrasingContent)); }, _isWhitespace: function(node) { return (node.nodeType === this.TEXT_NODE && node.textContent.trim().length === 0) || - (node.nodeType === this.ELEMENT_NODE && node.tagName === "BR"); + (node.nodeType === this.ELEMENT_NODE && node.tagName === "BR"); }, /** @@ -1371,7 +1392,7 @@ Readability.prototype = { * @param Element * @param Boolean normalizeSpaces (default: true) * @return string - **/ + **/ _getInnerText: function(e, normalizeSpaces) { normalizeSpaces = (typeof normalizeSpaces === "undefined") ? true : normalizeSpaces; var textContent = e.textContent.trim(); @@ -1388,7 +1409,7 @@ Readability.prototype = { * @param Element * @param string - what to split on. Default is "," * @return number (integer) - **/ + **/ _getCharCount: function(e, s) { s = s || ","; return this._getInnerText(e).split(s).length - 1; @@ -1400,7 +1421,7 @@ Readability.prototype = { * * @param Element * @return void - **/ + **/ _cleanStyles: function(e) { if (!e || e.tagName.toLowerCase() === "svg") return; @@ -1428,7 +1449,7 @@ Readability.prototype = { * * @param Element * @return number (float) - **/ + **/ _getLinkDensity: function(element) { var textLength = this._getInnerText(element).length; if (textLength === 0) @@ -1450,7 +1471,7 @@ Readability.prototype = { * * @param Element * @return number (Integer) - **/ + **/ _getClassWeight: function(e) { if (!this._flagIsActive(this.FLAG_WEIGHT_CLASSES)) return 0; @@ -1489,7 +1510,7 @@ Readability.prototype = { _clean: function(e, tag) { var isEmbed = ["object", "embed", "iframe"].indexOf(tag) !== -1; - this._removeNodes(e.getElementsByTagName(tag), function(element) { + this._removeNodes(this._getAllNodesWithTag(e, [tag]), function(element) { // Allow youtube and vimeo videos through as people usually want to see those. if (isEmbed) { // First, check the elements attributes to see if any of them contain youtube or vimeo @@ -1670,7 +1691,7 @@ Readability.prototype = { // without effecting the traversal. // // TODO: Consider taking into account original contentScore here. - this._removeNodes(e.getElementsByTagName(tag), function(node) { + this._removeNodes(this._getAllNodesWithTag(e, [tag]), function(node) { // First check if this node IS data table, in which case don't remove it. var isDataTable = function(t) { return t._readabilityDataTable; @@ -1704,10 +1725,7 @@ Readability.prototype = { var input = node.getElementsByTagName("input").length; var embedCount = 0; - var embeds = this._concatNodeLists( - node.getElementsByTagName("object"), - node.getElementsByTagName("embed"), - node.getElementsByTagName("iframe")); + var embeds = this._getAllNodesWithTag(node, ["object", "embed", "iframe"]); for (var i = 0; i < embeds.length; i++) { // If this embed has attribute that matches video regex, don't delete it. @@ -1729,13 +1747,13 @@ Readability.prototype = { var contentLength = this._getInnerText(node).length; var haveToRemove = - (img > 1 && p / img < 0.5 && !this._hasAncestorTag(node, "figure")) || - (!isList && li > p) || - (input > Math.floor(p/3)) || - (!isList && contentLength < 25 && (img === 0 || img > 2) && !this._hasAncestorTag(node, "figure")) || - (!isList && weight < 25 && linkDensity > 0.2) || - (weight >= 25 && linkDensity > 0.5) || - ((embedCount === 1 && contentLength < 75) || embedCount > 1); + (img > 1 && p / img < 0.5 && !this._hasAncestorTag(node, "figure")) || + (!isList && li > p) || + (input > Math.floor(p/3)) || + (!isList && contentLength < 25 && (img === 0 || img > 2) && !this._hasAncestorTag(node, "figure")) || + (!isList && weight < 25 && linkDensity > 0.2) || + (weight >= 25 && linkDensity > 0.5) || + ((embedCount === 1 && contentLength < 75) || embedCount > 1); return haveToRemove; } return false; @@ -1753,7 +1771,7 @@ Readability.prototype = { var endOfSearchMarkerNode = this._getNextNode(e, true); var next = this._getNextNode(e); while (next && next != endOfSearchMarkerNode) { - if (filter(next, next.className + " " + next.id)) { + if (filter.call(this, next, next.className + " " + next.id)) { next = this._removeAndGetNext(next); } else { next = this._getNextNode(next); @@ -1766,13 +1784,11 @@ Readability.prototype = { * * @param Element * @return void - **/ + **/ _cleanHeaders: function(e) { - for (var headerIndex = 1; headerIndex < 3; headerIndex += 1) { - this._removeNodes(e.getElementsByTagName("h" + headerIndex), function (header) { - return this._getClassWeight(header) < 0; - }); - } + this._removeNodes(this._getAllNodesWithTag(e, ["h1", "h2"]), function (header) { + return this._getClassWeight(header) < 0; + }); }, _flagIsActive: function(flag) { @@ -1784,7 +1800,11 @@ Readability.prototype = { }, _isProbablyVisible: function(node) { - return (!node.style || node.style.display != "none") && !node.hasAttribute("hidden"); + // Have to null-check node.style and node.className.indexOf to deal with SVG and MathML nodes. + return (!node.style || node.style.display != "none") + && !node.hasAttribute("hidden") + //check for "fallback-image" so that wikimedia math images are displayed + && (!node.hasAttribute("aria-hidden") || node.getAttribute("aria-hidden") != "true" || (node.className && node.className.indexOf && node.className.indexOf("fallback-image") !== -1)); }, /** diff --git a/lib/browser-polyfill.js b/lib/browser-polyfill.js index 0a5442b41..144fbf054 100644 --- a/lib/browser-polyfill.js +++ b/lib/browser-polyfill.js @@ -1,1135 +1,132 @@ -(function (global, factory) { - if (typeof define === "function" && define.amd) { - define("webextension-polyfill", ["module"], factory); - } else if (typeof exports !== "undefined") { - factory(module); - } else { - var mod = { - exports: {} +/* @@package_name - v@@version - @@timestamp */ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +if (typeof browser === "undefined" || Object.getPrototypeOf(browser) !== Object.prototype) { + const CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE = "The message port closed before a response was received."; + const SEND_RESPONSE_DEPRECATION_WARNING = "Returning a Promise is the preferred way to send a reply from an onMessage/onMessageExternal listener, as the sendResponse will be removed from the specs (See https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage)"; + + // Wrapping the bulk of this polyfill in a one-time-use function is a minor + // optimization for Firefox. Since Spidermonkey does not fully parse the + // contents of a function until the first time it's called, and since it will + // never actually need to be called, this allows the polyfill to be included + // in Firefox nearly for free. + const wrapAPIs = extensionAPIs => { + // NOTE: apiMetadata is associated to the content of the api-metadata.json file + // at build time by replacing the following "include" with the content of the + // JSON file. + const apiMetadata = {/* include("api-metadata.json") */}; + + if (Object.keys(apiMetadata).length === 0) { + throw new Error("api-metadata.json has not been included in browser-polyfill"); + } + + /** + * A WeakMap subclass which creates and stores a value for any key which does + * not exist when accessed, but behaves exactly as an ordinary WeakMap + * otherwise. + * + * @param {function} createItem + * A function which will be called in order to create the value for any + * key which does not exist, the first time it is accessed. The + * function receives, as its only argument, the key being created. + */ + class DefaultWeakMap extends WeakMap { + constructor(createItem, items = undefined) { + super(items); + this.createItem = createItem; + } + + get(key) { + if (!this.has(key)) { + this.set(key, this.createItem(key)); + } + + return super.get(key); + } + } + + /** + * Returns true if the given object is an object with a `then` method, and can + * therefore be assumed to behave as a Promise. + * + * @param {*} value The value to test. + * @returns {boolean} True if the value is thenable. + */ + const isThenable = value => { + return value && typeof value === "object" && typeof value.then === "function"; }; - factory(mod); - global.browser = mod.exports; - } -})(this, function (module) { - /* webextension-polyfill - v0.4.0 - Wed Feb 06 2019 11:58:31 */ - /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ - /* vim: set sts=2 sw=2 et tw=80: */ - /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - "use strict"; - if (typeof browser === "undefined" || Object.getPrototypeOf(browser) !== Object.prototype) { - const CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE = "The message port closed before a response was received."; - const SEND_RESPONSE_DEPRECATION_WARNING = "Returning a Promise is the preferred way to send a reply from an onMessage/onMessageExternal listener, as the sendResponse will be removed from the specs (See https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage)"; - - // Wrapping the bulk of this polyfill in a one-time-use function is a minor - // optimization for Firefox. Since Spidermonkey does not fully parse the - // contents of a function until the first time it's called, and since it will - // never actually need to be called, this allows the polyfill to be included - // in Firefox nearly for free. - const wrapAPIs = extensionAPIs => { - // NOTE: apiMetadata is associated to the content of the api-metadata.json file - // at build time by replacing the following "include" with the content of the - // JSON file. - const apiMetadata = { - "alarms": { - "clear": { - "minArgs": 0, - "maxArgs": 1 - }, - "clearAll": { - "minArgs": 0, - "maxArgs": 0 - }, - "get": { - "minArgs": 0, - "maxArgs": 1 - }, - "getAll": { - "minArgs": 0, - "maxArgs": 0 - } - }, - "bookmarks": { - "create": { - "minArgs": 1, - "maxArgs": 1 - }, - "get": { - "minArgs": 1, - "maxArgs": 1 - }, - "getChildren": { - "minArgs": 1, - "maxArgs": 1 - }, - "getRecent": { - "minArgs": 1, - "maxArgs": 1 - }, - "getSubTree": { - "minArgs": 1, - "maxArgs": 1 - }, - "getTree": { - "minArgs": 0, - "maxArgs": 0 - }, - "move": { - "minArgs": 2, - "maxArgs": 2 - }, - "remove": { - "minArgs": 1, - "maxArgs": 1 - }, - "removeTree": { - "minArgs": 1, - "maxArgs": 1 - }, - "search": { - "minArgs": 1, - "maxArgs": 1 - }, - "update": { - "minArgs": 2, - "maxArgs": 2 - } - }, - "browserAction": { - "disable": { - "minArgs": 0, - "maxArgs": 1, - "fallbackToNoCallback": true - }, - "enable": { - "minArgs": 0, - "maxArgs": 1, - "fallbackToNoCallback": true - }, - "getBadgeBackgroundColor": { - "minArgs": 1, - "maxArgs": 1 - }, - "getBadgeText": { - "minArgs": 1, - "maxArgs": 1 - }, - "getPopup": { - "minArgs": 1, - "maxArgs": 1 - }, - "getTitle": { - "minArgs": 1, - "maxArgs": 1 - }, - "openPopup": { - "minArgs": 0, - "maxArgs": 0 - }, - "setBadgeBackgroundColor": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - }, - "setBadgeText": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - }, - "setIcon": { - "minArgs": 1, - "maxArgs": 1 - }, - "setPopup": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - }, - "setTitle": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - } - }, - "browsingData": { - "remove": { - "minArgs": 2, - "maxArgs": 2 - }, - "removeCache": { - "minArgs": 1, - "maxArgs": 1 - }, - "removeCookies": { - "minArgs": 1, - "maxArgs": 1 - }, - "removeDownloads": { - "minArgs": 1, - "maxArgs": 1 - }, - "removeFormData": { - "minArgs": 1, - "maxArgs": 1 - }, - "removeHistory": { - "minArgs": 1, - "maxArgs": 1 - }, - "removeLocalStorage": { - "minArgs": 1, - "maxArgs": 1 - }, - "removePasswords": { - "minArgs": 1, - "maxArgs": 1 - }, - "removePluginData": { - "minArgs": 1, - "maxArgs": 1 - }, - "settings": { - "minArgs": 0, - "maxArgs": 0 - } - }, - "commands": { - "getAll": { - "minArgs": 0, - "maxArgs": 0 - } - }, - "contextMenus": { - "remove": { - "minArgs": 1, - "maxArgs": 1 - }, - "removeAll": { - "minArgs": 0, - "maxArgs": 0 - }, - "update": { - "minArgs": 2, - "maxArgs": 2 - } - }, - "cookies": { - "get": { - "minArgs": 1, - "maxArgs": 1 - }, - "getAll": { - "minArgs": 1, - "maxArgs": 1 - }, - "getAllCookieStores": { - "minArgs": 0, - "maxArgs": 0 - }, - "remove": { - "minArgs": 1, - "maxArgs": 1 - }, - "set": { - "minArgs": 1, - "maxArgs": 1 - } - }, - "devtools": { - "inspectedWindow": { - "eval": { - "minArgs": 1, - "maxArgs": 2, - "singleCallbackArg": false - } - }, - "panels": { - "create": { - "minArgs": 3, - "maxArgs": 3, - "singleCallbackArg": true - } - } - }, - "downloads": { - "cancel": { - "minArgs": 1, - "maxArgs": 1 - }, - "download": { - "minArgs": 1, - "maxArgs": 1 - }, - "erase": { - "minArgs": 1, - "maxArgs": 1 - }, - "getFileIcon": { - "minArgs": 1, - "maxArgs": 2 - }, - "open": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - }, - "pause": { - "minArgs": 1, - "maxArgs": 1 - }, - "removeFile": { - "minArgs": 1, - "maxArgs": 1 - }, - "resume": { - "minArgs": 1, - "maxArgs": 1 - }, - "search": { - "minArgs": 1, - "maxArgs": 1 - }, - "show": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - } - }, - "extension": { - "isAllowedFileSchemeAccess": { - "minArgs": 0, - "maxArgs": 0 - }, - "isAllowedIncognitoAccess": { - "minArgs": 0, - "maxArgs": 0 - } - }, - "history": { - "addUrl": { - "minArgs": 1, - "maxArgs": 1 - }, - "deleteAll": { - "minArgs": 0, - "maxArgs": 0 - }, - "deleteRange": { - "minArgs": 1, - "maxArgs": 1 - }, - "deleteUrl": { - "minArgs": 1, - "maxArgs": 1 - }, - "getVisits": { - "minArgs": 1, - "maxArgs": 1 - }, - "search": { - "minArgs": 1, - "maxArgs": 1 - } - }, - "i18n": { - "detectLanguage": { - "minArgs": 1, - "maxArgs": 1 - }, - "getAcceptLanguages": { - "minArgs": 0, - "maxArgs": 0 - } - }, - "identity": { - "launchWebAuthFlow": { - "minArgs": 1, - "maxArgs": 1 - } - }, - "idle": { - "queryState": { - "minArgs": 1, - "maxArgs": 1 - } - }, - "management": { - "get": { - "minArgs": 1, - "maxArgs": 1 - }, - "getAll": { - "minArgs": 0, - "maxArgs": 0 - }, - "getSelf": { - "minArgs": 0, - "maxArgs": 0 - }, - "setEnabled": { - "minArgs": 2, - "maxArgs": 2 - }, - "uninstallSelf": { - "minArgs": 0, - "maxArgs": 1 - } - }, - "notifications": { - "clear": { - "minArgs": 1, - "maxArgs": 1 - }, - "create": { - "minArgs": 1, - "maxArgs": 2 - }, - "getAll": { - "minArgs": 0, - "maxArgs": 0 - }, - "getPermissionLevel": { - "minArgs": 0, - "maxArgs": 0 - }, - "update": { - "minArgs": 2, - "maxArgs": 2 - } - }, - "pageAction": { - "getPopup": { - "minArgs": 1, - "maxArgs": 1 - }, - "getTitle": { - "minArgs": 1, - "maxArgs": 1 - }, - "hide": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - }, - "setIcon": { - "minArgs": 1, - "maxArgs": 1 - }, - "setPopup": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - }, - "setTitle": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - }, - "show": { - "minArgs": 1, - "maxArgs": 1, - "fallbackToNoCallback": true - } - }, - "permissions": { - "contains": { - "minArgs": 1, - "maxArgs": 1 - }, - "getAll": { - "minArgs": 0, - "maxArgs": 0 - }, - "remove": { - "minArgs": 1, - "maxArgs": 1 - }, - "request": { - "minArgs": 1, - "maxArgs": 1 - } - }, - "runtime": { - "getBackgroundPage": { - "minArgs": 0, - "maxArgs": 0 - }, - "getBrowserInfo": { - "minArgs": 0, - "maxArgs": 0 - }, - "getPlatformInfo": { - "minArgs": 0, - "maxArgs": 0 - }, - "openOptionsPage": { - "minArgs": 0, - "maxArgs": 0 - }, - "requestUpdateCheck": { - "minArgs": 0, - "maxArgs": 0 - }, - "sendMessage": { - "minArgs": 1, - "maxArgs": 3 - }, - "sendNativeMessage": { - "minArgs": 2, - "maxArgs": 2 - }, - "setUninstallURL": { - "minArgs": 1, - "maxArgs": 1 - } - }, - "sessions": { - "getDevices": { - "minArgs": 0, - "maxArgs": 1 - }, - "getRecentlyClosed": { - "minArgs": 0, - "maxArgs": 1 - }, - "restore": { - "minArgs": 0, - "maxArgs": 1 - } - }, - "storage": { - "local": { - "clear": { - "minArgs": 0, - "maxArgs": 0 - }, - "get": { - "minArgs": 0, - "maxArgs": 1 - }, - "getBytesInUse": { - "minArgs": 0, - "maxArgs": 1 - }, - "remove": { - "minArgs": 1, - "maxArgs": 1 - }, - "set": { - "minArgs": 1, - "maxArgs": 1 - } - }, - "managed": { - "get": { - "minArgs": 0, - "maxArgs": 1 - }, - "getBytesInUse": { - "minArgs": 0, - "maxArgs": 1 - } - }, - "sync": { - "clear": { - "minArgs": 0, - "maxArgs": 0 - }, - "get": { - "minArgs": 0, - "maxArgs": 1 - }, - "getBytesInUse": { - "minArgs": 0, - "maxArgs": 1 - }, - "remove": { - "minArgs": 1, - "maxArgs": 1 - }, - "set": { - "minArgs": 1, - "maxArgs": 1 - } - } - }, - "tabs": { - "captureVisibleTab": { - "minArgs": 0, - "maxArgs": 2 - }, - "create": { - "minArgs": 1, - "maxArgs": 1 - }, - "detectLanguage": { - "minArgs": 0, - "maxArgs": 1 - }, - "discard": { - "minArgs": 0, - "maxArgs": 1 - }, - "duplicate": { - "minArgs": 1, - "maxArgs": 1 - }, - "executeScript": { - "minArgs": 1, - "maxArgs": 2 - }, - "get": { - "minArgs": 1, - "maxArgs": 1 - }, - "getCurrent": { - "minArgs": 0, - "maxArgs": 0 - }, - "getZoom": { - "minArgs": 0, - "maxArgs": 1 - }, - "getZoomSettings": { - "minArgs": 0, - "maxArgs": 1 - }, - "highlight": { - "minArgs": 1, - "maxArgs": 1 - }, - "insertCSS": { - "minArgs": 1, - "maxArgs": 2 - }, - "move": { - "minArgs": 2, - "maxArgs": 2 - }, - "query": { - "minArgs": 1, - "maxArgs": 1 - }, - "reload": { - "minArgs": 0, - "maxArgs": 2 - }, - "remove": { - "minArgs": 1, - "maxArgs": 1 - }, - "removeCSS": { - "minArgs": 1, - "maxArgs": 2 - }, - "sendMessage": { - "minArgs": 2, - "maxArgs": 3 - }, - "setZoom": { - "minArgs": 1, - "maxArgs": 2 - }, - "setZoomSettings": { - "minArgs": 1, - "maxArgs": 2 - }, - "update": { - "minArgs": 1, - "maxArgs": 2 - } - }, - "topSites": { - "get": { - "minArgs": 0, - "maxArgs": 0 - } - }, - "webNavigation": { - "getAllFrames": { - "minArgs": 1, - "maxArgs": 1 - }, - "getFrame": { - "minArgs": 1, - "maxArgs": 1 - } - }, - "webRequest": { - "handlerBehaviorChanged": { - "minArgs": 0, - "maxArgs": 0 - } - }, - "windows": { - "create": { - "minArgs": 0, - "maxArgs": 1 - }, - "get": { - "minArgs": 1, - "maxArgs": 2 - }, - "getAll": { - "minArgs": 0, - "maxArgs": 1 - }, - "getCurrent": { - "minArgs": 0, - "maxArgs": 1 - }, - "getLastFocused": { - "minArgs": 0, - "maxArgs": 1 - }, - "remove": { - "minArgs": 1, - "maxArgs": 1 - }, - "update": { - "minArgs": 2, - "maxArgs": 2 - } - } - }; - - if (Object.keys(apiMetadata).length === 0) { - throw new Error("api-metadata.json has not been included in browser-polyfill"); - } - - /** - * A WeakMap subclass which creates and stores a value for any key which does - * not exist when accessed, but behaves exactly as an ordinary WeakMap - * otherwise. - * - * @param {function} createItem - * A function which will be called in order to create the value for any - * key which does not exist, the first time it is accessed. The - * function receives, as its only argument, the key being created. - */ - class DefaultWeakMap extends WeakMap { - constructor(createItem, items = undefined) { - super(items); - this.createItem = createItem; - } - - get(key) { - if (!this.has(key)) { - this.set(key, this.createItem(key)); - } - - return super.get(key); - } - } - - /** - * Returns true if the given object is an object with a `then` method, and can - * therefore be assumed to behave as a Promise. - * - * @param {*} value The value to test. - * @returns {boolean} True if the value is thenable. - */ - const isThenable = value => { - return value && typeof value === "object" && typeof value.then === "function"; - }; - - /** - * Creates and returns a function which, when called, will resolve or reject - * the given promise based on how it is called: - * - * - If, when called, `chrome.runtime.lastError` contains a non-null object, - * the promise is rejected with that value. - * - If the function is called with exactly one argument, the promise is - * resolved to that value. - * - Otherwise, the promise is resolved to an array containing all of the - * function's arguments. - * - * @param {object} promise - * An object containing the resolution and rejection functions of a - * promise. - * @param {function} promise.resolve - * The promise's resolution function. - * @param {function} promise.rejection - * The promise's rejection function. - * @param {object} metadata - * Metadata about the wrapped method which has created the callback. - * @param {integer} metadata.maxResolvedArgs - * The maximum number of arguments which may be passed to the - * callback created by the wrapped async function. - * - * @returns {function} - * The generated callback function. - */ - const makeCallback = (promise, metadata) => { - return (...callbackArgs) => { - if (extensionAPIs.runtime.lastError) { - promise.reject(extensionAPIs.runtime.lastError); - } else if (metadata.singleCallbackArg || callbackArgs.length <= 1 && metadata.singleCallbackArg !== false) { - promise.resolve(callbackArgs[0]); - } else { - promise.resolve(callbackArgs); - } - }; - }; - - const pluralizeArguments = numArgs => numArgs == 1 ? "argument" : "arguments"; - - /** - * Creates a wrapper function for a method with the given name and metadata. - * - * @param {string} name - * The name of the method which is being wrapped. - * @param {object} metadata - * Metadata about the method being wrapped. - * @param {integer} metadata.minArgs - * The minimum number of arguments which must be passed to the - * function. If called with fewer than this number of arguments, the - * wrapper will raise an exception. - * @param {integer} metadata.maxArgs - * The maximum number of arguments which may be passed to the - * function. If called with more than this number of arguments, the - * wrapper will raise an exception. - * @param {integer} metadata.maxResolvedArgs - * The maximum number of arguments which may be passed to the - * callback created by the wrapped async function. - * - * @returns {function(object, ...*)} - * The generated wrapper function. - */ - const wrapAsyncFunction = (name, metadata) => { - return function asyncFunctionWrapper(target, ...args) { - if (args.length < metadata.minArgs) { - throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`); - } - - if (args.length > metadata.maxArgs) { - throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`); - } - - return new Promise((resolve, reject) => { - if (metadata.fallbackToNoCallback) { - // This API method has currently no callback on Chrome, but it return a promise on Firefox, - // and so the polyfill will try to call it with a callback first, and it will fallback - // to not passing the callback if the first call fails. - try { - target[name](...args, makeCallback({ resolve, reject }, metadata)); - } catch (cbError) { - console.warn(`${name} API method doesn't seem to support the callback parameter, ` + "falling back to call it without a callback: ", cbError); - - target[name](...args); - - // Update the API method metadata, so that the next API calls will not try to - // use the unsupported callback anymore. - metadata.fallbackToNoCallback = false; - metadata.noCallback = true; - - resolve(); - } - } else if (metadata.noCallback) { - target[name](...args); - resolve(); - } else { - target[name](...args, makeCallback({ resolve, reject }, metadata)); - } - }); - }; - }; - - /** - * Wraps an existing method of the target object, so that calls to it are - * intercepted by the given wrapper function. The wrapper function receives, - * as its first argument, the original `target` object, followed by each of - * the arguments passed to the original method. - * - * @param {object} target - * The original target object that the wrapped method belongs to. - * @param {function} method - * The method being wrapped. This is used as the target of the Proxy - * object which is created to wrap the method. - * @param {function} wrapper - * The wrapper function which is called in place of a direct invocation - * of the wrapped method. - * - * @returns {Proxy} - * A Proxy object for the given method, which invokes the given wrapper - * method in its place. - */ - const wrapMethod = (target, method, wrapper) => { - return new Proxy(method, { - apply(targetMethod, thisObj, args) { - return wrapper.call(thisObj, target, ...args); - } - }); - }; - - let hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty); - - /** - * Wraps an object in a Proxy which intercepts and wraps certain methods - * based on the given `wrappers` and `metadata` objects. - * - * @param {object} target - * The target object to wrap. - * - * @param {object} [wrappers = {}] - * An object tree containing wrapper functions for special cases. Any - * function present in this object tree is called in place of the - * method in the same location in the `target` object tree. These - * wrapper methods are invoked as described in {@see wrapMethod}. - * - * @param {object} [metadata = {}] - * An object tree containing metadata used to automatically generate - * Promise-based wrapper functions for asynchronous. Any function in - * the `target` object tree which has a corresponding metadata object - * in the same location in the `metadata` tree is replaced with an - * automatically-generated wrapper function, as described in - * {@see wrapAsyncFunction} - * - * @returns {Proxy} - */ - const wrapObject = (target, wrappers = {}, metadata = {}) => { - let cache = Object.create(null); - let handlers = { - has(proxyTarget, prop) { - return prop in target || prop in cache; - }, - - get(proxyTarget, prop, receiver) { - if (prop in cache) { - return cache[prop]; - } - - if (!(prop in target)) { - return undefined; - } - - let value = target[prop]; - - if (typeof value === "function") { - // This is a method on the underlying object. Check if we need to do - // any wrapping. - - if (typeof wrappers[prop] === "function") { - // We have a special-case wrapper for this method. - value = wrapMethod(target, target[prop], wrappers[prop]); - } else if (hasOwnProperty(metadata, prop)) { - // This is an async method that we have metadata for. Create a - // Promise wrapper for it. - let wrapper = wrapAsyncFunction(prop, metadata[prop]); - value = wrapMethod(target, target[prop], wrapper); - } else { - // This is a method that we don't know or care about. Return the - // original method, bound to the underlying object. - value = value.bind(target); - } - } else if (typeof value === "object" && value !== null && (hasOwnProperty(wrappers, prop) || hasOwnProperty(metadata, prop))) { - // This is an object that we need to do some wrapping for the children - // of. Create a sub-object wrapper for it with the appropriate child - // metadata. - value = wrapObject(value, wrappers[prop], metadata[prop]); - } else { - // We don't need to do any wrapping for this property, - // so just forward all access to the underlying object. - Object.defineProperty(cache, prop, { - configurable: true, - enumerable: true, - get() { - return target[prop]; - }, - set(value) { - target[prop] = value; - } - }); - - return value; - } - - cache[prop] = value; - return value; - }, - - set(proxyTarget, prop, value, receiver) { - if (prop in cache) { - cache[prop] = value; - } else { - target[prop] = value; - } - return true; - }, - - defineProperty(proxyTarget, prop, desc) { - return Reflect.defineProperty(cache, prop, desc); - }, - - deleteProperty(proxyTarget, prop) { - return Reflect.deleteProperty(cache, prop); - } - }; - - // Per contract of the Proxy API, the "get" proxy handler must return the - // original value of the target if that value is declared read-only and - // non-configurable. For this reason, we create an object with the - // prototype set to `target` instead of using `target` directly. - // Otherwise we cannot return a custom object for APIs that - // are declared read-only and non-configurable, such as `chrome.devtools`. - // - // The proxy handlers themselves will still use the original `target` - // instead of the `proxyTarget`, so that the methods and properties are - // dereferenced via the original targets. - let proxyTarget = Object.create(target); - return new Proxy(proxyTarget, handlers); - }; - - /** - * Creates a set of wrapper functions for an event object, which handles - * wrapping of listener functions that those messages are passed. - * - * A single wrapper is created for each listener function, and stored in a - * map. Subsequent calls to `addListener`, `hasListener`, or `removeListener` - * retrieve the original wrapper, so that attempts to remove a - * previously-added listener work as expected. - * - * @param {DefaultWeakMap} wrapperMap - * A DefaultWeakMap object which will create the appropriate wrapper - * for a given listener function when one does not exist, and retrieve - * an existing one when it does. - * - * @returns {object} - */ - const wrapEvent = wrapperMap => ({ - addListener(target, listener, ...args) { - target.addListener(wrapperMap.get(listener), ...args); - }, - - hasListener(target, listener) { - return target.hasListener(wrapperMap.get(listener)); - }, - - removeListener(target, listener) { - target.removeListener(wrapperMap.get(listener)); - } - }); - - // Keep track if the deprecation warning has been logged at least once. - let loggedSendResponseDeprecationWarning = false; - - const onMessageWrappers = new DefaultWeakMap(listener => { - if (typeof listener !== "function") { - return listener; - } - - /** - * Wraps a message listener function so that it may send responses based on - * its return value, rather than by returning a sentinel value and calling a - * callback. If the listener function returns a Promise, the response is - * sent when the promise either resolves or rejects. - * - * @param {*} message - * The message sent by the other end of the channel. - * @param {object} sender - * Details about the sender of the message. - * @param {function(*)} sendResponse - * A callback which, when called with an arbitrary argument, sends - * that value as a response. - * @returns {boolean} - * True if the wrapped listener returned a Promise, which will later - * yield a response. False otherwise. - */ - return function onMessage(message, sender, sendResponse) { - let didCallSendResponse = false; - - let wrappedSendResponse; - let sendResponsePromise = new Promise(resolve => { - wrappedSendResponse = function (response) { - if (!loggedSendResponseDeprecationWarning) { - console.warn(SEND_RESPONSE_DEPRECATION_WARNING, new Error().stack); - loggedSendResponseDeprecationWarning = true; - } - didCallSendResponse = true; - resolve(response); - }; - }); - - let result; - try { - result = listener(message, sender, wrappedSendResponse); - } catch (err) { - result = Promise.reject(err); - } - - const isResultThenable = result !== true && isThenable(result); - - // If the listener didn't returned true or a Promise, or called - // wrappedSendResponse synchronously, we can exit earlier - // because there will be no response sent from this listener. - if (result !== true && !isResultThenable && !didCallSendResponse) { - return false; - } - - // A small helper to send the message if the promise resolves - // and an error if the promise rejects (a wrapped sendMessage has - // to translate the message into a resolved promise or a rejected - // promise). - const sendPromisedResult = promise => { - promise.then(msg => { - // send the message value. - sendResponse(msg); - }, error => { - // Send a JSON representation of the error if the rejected value - // is an instance of error, or the object itself otherwise. - let message; - if (error && (error instanceof Error || typeof error.message === "string")) { - message = error.message; - } else { - message = "An unexpected error occurred"; - } - - sendResponse({ - __mozWebExtensionPolyfillReject__: true, - message - }); - }).catch(err => { - // Print an error on the console if unable to send the response. - console.error("Failed to send onMessage rejected reply", err); - }); - }; - - // If the listener returned a Promise, send the resolved value as a - // result, otherwise wait the promise related to the wrappedSendResponse - // callback to resolve and send it as a response. - if (isResultThenable) { - sendPromisedResult(result); - } else { - sendPromisedResult(sendResponsePromise); - } - - // Let Chrome know that the listener is replying. - return true; - }; - }); - - const wrappedSendMessageCallback = ({ reject, resolve }, reply) => { + /** + * Creates and returns a function which, when called, will resolve or reject + * the given promise based on how it is called: + * + * - If, when called, `chrome.runtime.lastError` contains a non-null object, + * the promise is rejected with that value. + * - If the function is called with exactly one argument, the promise is + * resolved to that value. + * - Otherwise, the promise is resolved to an array containing all of the + * function's arguments. + * + * @param {object} promise + * An object containing the resolution and rejection functions of a + * promise. + * @param {function} promise.resolve + * The promise's resolution function. + * @param {function} promise.rejection + * The promise's rejection function. + * @param {object} metadata + * Metadata about the wrapped method which has created the callback. + * @param {integer} metadata.maxResolvedArgs + * The maximum number of arguments which may be passed to the + * callback created by the wrapped async function. + * + * @returns {function} + * The generated callback function. + */ + const makeCallback = (promise, metadata) => { + return (...callbackArgs) => { if (extensionAPIs.runtime.lastError) { - // Detect when none of the listeners replied to the sendMessage call and resolve - // the promise to undefined as in Firefox. - // See https://github.com/mozilla/webextension-polyfill/issues/130 - if (extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE) { - resolve(); - } else { - reject(extensionAPIs.runtime.lastError); - } - } else if (reply && reply.__mozWebExtensionPolyfillReject__) { - // Convert back the JSON representation of the error into - // an Error instance. - reject(new Error(reply.message)); + promise.reject(extensionAPIs.runtime.lastError); + } else if (metadata.singleCallbackArg || + (callbackArgs.length <= 1 && metadata.singleCallbackArg !== false)) { + promise.resolve(callbackArgs[0]); } else { - resolve(reply); + promise.resolve(callbackArgs); } }; + }; - const wrappedSendMessage = (name, metadata, apiNamespaceObj, ...args) => { + const pluralizeArguments = (numArgs) => numArgs == 1 ? "argument" : "arguments"; + + /** + * Creates a wrapper function for a method with the given name and metadata. + * + * @param {string} name + * The name of the method which is being wrapped. + * @param {object} metadata + * Metadata about the method being wrapped. + * @param {integer} metadata.minArgs + * The minimum number of arguments which must be passed to the + * function. If called with fewer than this number of arguments, the + * wrapper will raise an exception. + * @param {integer} metadata.maxArgs + * The maximum number of arguments which may be passed to the + * function. If called with more than this number of arguments, the + * wrapper will raise an exception. + * @param {integer} metadata.maxResolvedArgs + * The maximum number of arguments which may be passed to the + * callback created by the wrapped async function. + * + * @returns {function(object, ...*)} + * The generated wrapper function. + */ + const wrapAsyncFunction = (name, metadata) => { + return function asyncFunctionWrapper(target, ...args) { if (args.length < metadata.minArgs) { throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`); } @@ -1139,49 +136,378 @@ } return new Promise((resolve, reject) => { - const wrappedCb = wrappedSendMessageCallback.bind(null, { resolve, reject }); - args.push(wrappedCb); - apiNamespaceObj.sendMessage(...args); + if (metadata.fallbackToNoCallback) { + // This API method has currently no callback on Chrome, but it return a promise on Firefox, + // and so the polyfill will try to call it with a callback first, and it will fallback + // to not passing the callback if the first call fails. + try { + target[name](...args, makeCallback({resolve, reject}, metadata)); + } catch (cbError) { + console.warn(`${name} API method doesn't seem to support the callback parameter, ` + + "falling back to call it without a callback: ", cbError); + + target[name](...args); + + // Update the API method metadata, so that the next API calls will not try to + // use the unsupported callback anymore. + metadata.fallbackToNoCallback = false; + metadata.noCallback = true; + + resolve(); + } + } else if (metadata.noCallback) { + target[name](...args); + resolve(); + } else { + target[name](...args, makeCallback({resolve, reject}, metadata)); + } }); }; - - const staticWrappers = { - runtime: { - onMessage: wrapEvent(onMessageWrappers), - onMessageExternal: wrapEvent(onMessageWrappers), - sendMessage: wrappedSendMessage.bind(null, "sendMessage", { minArgs: 1, maxArgs: 3 }) - }, - tabs: { - sendMessage: wrappedSendMessage.bind(null, "sendMessage", { minArgs: 2, maxArgs: 3 }) - } - }; - const settingMetadata = { - clear: { minArgs: 1, maxArgs: 1 }, - get: { minArgs: 1, maxArgs: 1 }, - set: { minArgs: 1, maxArgs: 1 } - }; - apiMetadata.privacy = { - network: { - networkPredictionEnabled: settingMetadata, - webRTCIPHandlingPolicy: settingMetadata - }, - services: { - passwordSavingEnabled: settingMetadata - }, - websites: { - hyperlinkAuditingEnabled: settingMetadata, - referrersEnabled: settingMetadata - } - }; - - return wrapObject(extensionAPIs, staticWrappers, apiMetadata); }; - // The build process adds a UMD wrapper around this file, which makes the - // `module` variable available. - module.exports = wrapAPIs(chrome); - } else { - module.exports = browser; + /** + * Wraps an existing method of the target object, so that calls to it are + * intercepted by the given wrapper function. The wrapper function receives, + * as its first argument, the original `target` object, followed by each of + * the arguments passed to the original method. + * + * @param {object} target + * The original target object that the wrapped method belongs to. + * @param {function} method + * The method being wrapped. This is used as the target of the Proxy + * object which is created to wrap the method. + * @param {function} wrapper + * The wrapper function which is called in place of a direct invocation + * of the wrapped method. + * + * @returns {Proxy} + * A Proxy object for the given method, which invokes the given wrapper + * method in its place. + */ + const wrapMethod = (target, method, wrapper) => { + return new Proxy(method, { + apply(targetMethod, thisObj, args) { + return wrapper.call(thisObj, target, ...args); + }, + }); + }; + + let hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty); + + /** + * Wraps an object in a Proxy which intercepts and wraps certain methods + * based on the given `wrappers` and `metadata` objects. + * + * @param {object} target + * The target object to wrap. + * + * @param {object} [wrappers = {}] + * An object tree containing wrapper functions for special cases. Any + * function present in this object tree is called in place of the + * method in the same location in the `target` object tree. These + * wrapper methods are invoked as described in {@see wrapMethod}. + * + * @param {object} [metadata = {}] + * An object tree containing metadata used to automatically generate + * Promise-based wrapper functions for asynchronous. Any function in + * the `target` object tree which has a corresponding metadata object + * in the same location in the `metadata` tree is replaced with an + * automatically-generated wrapper function, as described in + * {@see wrapAsyncFunction} + * + * @returns {Proxy} + */ + const wrapObject = (target, wrappers = {}, metadata = {}) => { + let cache = Object.create(null); + let handlers = { + has(proxyTarget, prop) { + return prop in target || prop in cache; + }, + + get(proxyTarget, prop, receiver) { + if (prop in cache) { + return cache[prop]; + } + + if (!(prop in target)) { + return undefined; + } + + let value = target[prop]; + + if (typeof value === "function") { + // This is a method on the underlying object. Check if we need to do + // any wrapping. + + if (typeof wrappers[prop] === "function") { + // We have a special-case wrapper for this method. + value = wrapMethod(target, target[prop], wrappers[prop]); + } else if (hasOwnProperty(metadata, prop)) { + // This is an async method that we have metadata for. Create a + // Promise wrapper for it. + let wrapper = wrapAsyncFunction(prop, metadata[prop]); + value = wrapMethod(target, target[prop], wrapper); + } else { + // This is a method that we don't know or care about. Return the + // original method, bound to the underlying object. + value = value.bind(target); + } + } else if (typeof value === "object" && value !== null && + (hasOwnProperty(wrappers, prop) || + hasOwnProperty(metadata, prop))) { + // This is an object that we need to do some wrapping for the children + // of. Create a sub-object wrapper for it with the appropriate child + // metadata. + value = wrapObject(value, wrappers[prop], metadata[prop]); + } else if (hasOwnProperty(metadata, "*")) { + // Wrap all properties in * namespace. + value = wrapObject(value, wrappers[prop], metadata["*"]); + } else { + // We don't need to do any wrapping for this property, + // so just forward all access to the underlying object. + Object.defineProperty(cache, prop, { + configurable: true, + enumerable: true, + get() { + return target[prop]; + }, + set(value) { + target[prop] = value; + }, + }); + + return value; + } + + cache[prop] = value; + return value; + }, + + set(proxyTarget, prop, value, receiver) { + if (prop in cache) { + cache[prop] = value; + } else { + target[prop] = value; + } + return true; + }, + + defineProperty(proxyTarget, prop, desc) { + return Reflect.defineProperty(cache, prop, desc); + }, + + deleteProperty(proxyTarget, prop) { + return Reflect.deleteProperty(cache, prop); + }, + }; + + // Per contract of the Proxy API, the "get" proxy handler must return the + // original value of the target if that value is declared read-only and + // non-configurable. For this reason, we create an object with the + // prototype set to `target` instead of using `target` directly. + // Otherwise we cannot return a custom object for APIs that + // are declared read-only and non-configurable, such as `chrome.devtools`. + // + // The proxy handlers themselves will still use the original `target` + // instead of the `proxyTarget`, so that the methods and properties are + // dereferenced via the original targets. + let proxyTarget = Object.create(target); + return new Proxy(proxyTarget, handlers); + }; + + /** + * Creates a set of wrapper functions for an event object, which handles + * wrapping of listener functions that those messages are passed. + * + * A single wrapper is created for each listener function, and stored in a + * map. Subsequent calls to `addListener`, `hasListener`, or `removeListener` + * retrieve the original wrapper, so that attempts to remove a + * previously-added listener work as expected. + * + * @param {DefaultWeakMap} wrapperMap + * A DefaultWeakMap object which will create the appropriate wrapper + * for a given listener function when one does not exist, and retrieve + * an existing one when it does. + * + * @returns {object} + */ + const wrapEvent = wrapperMap => ({ + addListener(target, listener, ...args) { + target.addListener(wrapperMap.get(listener), ...args); + }, + + hasListener(target, listener) { + return target.hasListener(wrapperMap.get(listener)); + }, + + removeListener(target, listener) { + target.removeListener(wrapperMap.get(listener)); + }, + }); + + // Keep track if the deprecation warning has been logged at least once. + let loggedSendResponseDeprecationWarning = false; + + const onMessageWrappers = new DefaultWeakMap(listener => { + if (typeof listener !== "function") { + return listener; + } + + /** + * Wraps a message listener function so that it may send responses based on + * its return value, rather than by returning a sentinel value and calling a + * callback. If the listener function returns a Promise, the response is + * sent when the promise either resolves or rejects. + * + * @param {*} message + * The message sent by the other end of the channel. + * @param {object} sender + * Details about the sender of the message. + * @param {function(*)} sendResponse + * A callback which, when called with an arbitrary argument, sends + * that value as a response. + * @returns {boolean} + * True if the wrapped listener returned a Promise, which will later + * yield a response. False otherwise. + */ + return function onMessage(message, sender, sendResponse) { + let didCallSendResponse = false; + + let wrappedSendResponse; + let sendResponsePromise = new Promise(resolve => { + wrappedSendResponse = function(response) { + if (!loggedSendResponseDeprecationWarning) { + console.warn(SEND_RESPONSE_DEPRECATION_WARNING, new Error().stack); + loggedSendResponseDeprecationWarning = true; + } + didCallSendResponse = true; + resolve(response); + }; + }); + + let result; + try { + result = listener(message, sender, wrappedSendResponse); + } catch (err) { + result = Promise.reject(err); + } + + const isResultThenable = result !== true && isThenable(result); + + // If the listener didn't returned true or a Promise, or called + // wrappedSendResponse synchronously, we can exit earlier + // because there will be no response sent from this listener. + if (result !== true && !isResultThenable && !didCallSendResponse) { + return false; + } + + // A small helper to send the message if the promise resolves + // and an error if the promise rejects (a wrapped sendMessage has + // to translate the message into a resolved promise or a rejected + // promise). + const sendPromisedResult = (promise) => { + promise.then(msg => { + // send the message value. + sendResponse(msg); + }, error => { + // Send a JSON representation of the error if the rejected value + // is an instance of error, or the object itself otherwise. + let message; + if (error && (error instanceof Error || + typeof error.message === "string")) { + message = error.message; + } else { + message = "An unexpected error occurred"; + } + + sendResponse({ + __mozWebExtensionPolyfillReject__: true, + message, + }); + }).catch(err => { + // Print an error on the console if unable to send the response. + console.error("Failed to send onMessage rejected reply", err); + }); + }; + + // If the listener returned a Promise, send the resolved value as a + // result, otherwise wait the promise related to the wrappedSendResponse + // callback to resolve and send it as a response. + if (isResultThenable) { + sendPromisedResult(result); + } else { + sendPromisedResult(sendResponsePromise); + } + + // Let Chrome know that the listener is replying. + return true; + }; + }); + + const wrappedSendMessageCallback = ({reject, resolve}, reply) => { + if (extensionAPIs.runtime.lastError) { + // Detect when none of the listeners replied to the sendMessage call and resolve + // the promise to undefined as in Firefox. + // See https://github.com/mozilla/webextension-polyfill/issues/130 + if (extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE) { + resolve(); + } else { + reject(extensionAPIs.runtime.lastError); + } + } else if (reply && reply.__mozWebExtensionPolyfillReject__) { + // Convert back the JSON representation of the error into + // an Error instance. + reject(new Error(reply.message)); + } else { + resolve(reply); + } + }; + + const wrappedSendMessage = (name, metadata, apiNamespaceObj, ...args) => { + if (args.length < metadata.minArgs) { + throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`); + } + + if (args.length > metadata.maxArgs) { + throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`); + } + + return new Promise((resolve, reject) => { + const wrappedCb = wrappedSendMessageCallback.bind(null, {resolve, reject}); + args.push(wrappedCb); + apiNamespaceObj.sendMessage(...args); + }); + }; + + const staticWrappers = { + runtime: { + onMessage: wrapEvent(onMessageWrappers), + onMessageExternal: wrapEvent(onMessageWrappers), + sendMessage: wrappedSendMessage.bind(null, "sendMessage", {minArgs: 1, maxArgs: 3}), + }, + tabs: { + sendMessage: wrappedSendMessage.bind(null, "sendMessage", {minArgs: 2, maxArgs: 3}), + }, + }; + const settingMetadata = { + clear: {minArgs: 1, maxArgs: 1}, + get: {minArgs: 1, maxArgs: 1}, + set: {minArgs: 1, maxArgs: 1}, + }; + apiMetadata.privacy = { + network: {"*": settingMetadata}, + services: {"*": settingMetadata}, + websites: {"*": settingMetadata}, + }; + + return wrapObject(extensionAPIs, staticWrappers, apiMetadata); + }; + + if (typeof chrome != "object" || !chrome || !chrome.runtime || !chrome.runtime.id) { + throw new Error("This script should only be loaded in a browser extension."); } -}); -//# sourceMappingURL=browser-polyfill.js.map \ No newline at end of file + + // The build process adds a UMD wrapper around this file, which makes the + // `module` variable available. + browser = wrapAPIs(chrome); +} diff --git a/lib/cash.min.js b/lib/cash.min.js index 39e635b95..044700612 100644 --- a/lib/cash.min.js +++ b/lib/cash.min.js @@ -1,37 +1,40 @@ /* MIT https://github.com/kenwheeler/cash */ (function(){ -'use strict';var e=document,g=window,k=e.createElement("div"),l=Array.prototype,m=l.filter,n=l.indexOf,aa=l.map,q=l.push,r=l.reverse,u=l.slice,v=l.some,ba=l.splice,ca=/^#[\w-]*$/,da=/^\.[\w-]*$/,ea=/<.+>/,fa=/^\w+$/;function x(a,b){void 0===b&&(b=e);return b&&9===b.nodeType||b&&1===b.nodeType?da.test(a)?b.getElementsByClassName(a.slice(1)):fa.test(a)?b.getElementsByTagName(a):b.querySelectorAll(a):[]} -var y=function(){function a(a,c){void 0===c&&(c=e);if(a){if(a instanceof y)return a;var b=a;if(z(a)){if(b=c instanceof y?c[0]:c,b=ca.test(a)?b.getElementById(a.slice(1)):ea.test(a)?A(a):x(a,b),!b)return}else if(B(a))return this.ready(a);if(b.nodeType||b===g)b=[b];this.length=b.length;a=0;for(c=this.length;aa?a+this.length:a]};y.prototype.eq=function(a){return C(this.get(a))};y.prototype.first=function(){return this.eq(0)};y.prototype.last=function(){return this.eq(-1)};y.prototype.map=function(a){return C(aa.call(this,function(b,c){return a.call(b,c,b)}))};y.prototype.slice=function(){return C(u.apply(this,arguments))};var ha=/-([a-z])/g; -function ia(a,b){return b.toUpperCase()}function D(a){return a.replace(ha,ia)}C.camelCase=D;function E(a,b){for(var c=0,d=a.length;cc?0:1;darguments.length?this[0]&&this[0][a]:this.each(function(c,f){f[a]=b});for(var c in a)this.prop(c,a[c]);return this}};function L(a){return z(a)?function(b,c){return G(c,a)}:B(a)?a:a instanceof y?function(b,c){return a.is(c)}:function(b,c){return c===a}}y.prototype.filter=function(a){if(!a)return C();var b=L(a);return C(m.call(this,function(a,d){return b.call(a,d,a)}))}; -function M(a,b){return b&&a.length?a.filter(b):a}var ja=/\S+/g;function N(a){return z(a)?a.match(ja)||[]:[]}y.prototype.hasClass=function(a){return a&&v.call(this,function(b){return b.classList.contains(a)})};y.prototype.removeAttr=function(a){var b=N(a);return b.length?this.each(function(a,d){E(b,function(a,b){d.removeAttribute(b)})}):this}; -y.prototype.attr=function(a,b){if(a){if(z(a)){if(2>arguments.length){if(!this[0])return;var c=this[0].getAttribute(a);return null===c?void 0:c}return void 0===b?this:null===b?this.removeAttr(a):this.each(function(c,f){f.setAttribute(a,b)})}for(c in a)this.attr(c,a[c]);return this}};y.prototype.toggleClass=function(a,b){var c=N(a),d=void 0!==b;return c.length?this.each(function(a,h){E(c,function(a,c){d?b?h.classList.add(c):h.classList.remove(c):h.classList.toggle(c)})}):this}; -y.prototype.addClass=function(a){return this.toggleClass(a,!0)};y.prototype.removeClass=function(a){return arguments.length?this.toggleClass(a,!1):this.attr("class","")};function O(a){return 1arguments.length)return this[0]&&P(this[0],a,c);if(!a)return this;b=oa(a,b,c);return this.each(function(d,h){h&&1===h.nodeType&&(c?h.style.setProperty(a,b):h.style[a]=b)})}for(var d in a)this.css(d,a[d]);return this};function pa(a,b){a=a.dataset?a.dataset[b]||a.dataset[D(b)]:a.getAttribute("data-"+b);try{return JSON.parse(a)}catch(c){}return a}var qa=/^data-(.+)/; -y.prototype.data=function(a,b){var c=this;if(!a){if(!this[0])return;var d={};E(this[0].attributes,function(a,b){(a=b.name.match(qa))&&(d[a[1]]=c.data(a[1]))});return d}if(z(a))return void 0===b?this[0]&&pa(this[0],a):this.each(function(c,d){c=b;try{c=JSON.stringify(c)}catch(w){}d.dataset?d.dataset[D(a)]=c:d.setAttribute("data-"+a,c)});for(var f in a)this.data(f,a[f]);return this}; -function ra(a,b){return Q(a,"border"+(b?"Left":"Top")+"Width")+Q(a,"padding"+(b?"Left":"Top"))+Q(a,"padding"+(b?"Right":"Bottom"))+Q(a,"border"+(b?"Right":"Bottom")+"Width")}E(["Width","Height"],function(a,b){y.prototype["inner"+b]=function(){if(this[0])return I(this[0])?g["inner"+b]:this[0]["client"+b]}}); -E(["width","height"],function(a,b){y.prototype[b]=function(c){if(!this[0])return void 0===c?void 0:this;if(!arguments.length)return I(this[0])?this[0][D("outer-"+b)]:this[0].getBoundingClientRect()[b]-ra(this[0],!a);var d=parseInt(c,10);return this.each(function(c,h){h&&1===h.nodeType&&(c=P(h,"boxSizing"),h.style[b]=oa(b,d+("border-box"===c?ra(h,!a):0)))})}}); -E(["Width","Height"],function(a,b){y.prototype["outer"+b]=function(c){if(this[0])return I(this[0])?g["outer"+b]:this[0]["offset"+b]+(c?Q(this[0],"margin"+(a?"Top":"Left"))+Q(this[0],"margin"+(a?"Bottom":"Right")):0)}});var T={}; -y.prototype.toggle=function(a){return this.each(function(b,c){if(a=void 0!==a?a:"none"===P(c,"display")){if(c.style.display="","none"===P(c,"display")){b=c.style;c=c.tagName;if(T[c])c=T[c];else{var d=e.createElement(c);e.body.appendChild(d);var f=P(d,"display");e.body.removeChild(d);c=T[c]="none"!==f?f:"block"}b.display=c}}else c.style.display="none"})};y.prototype.hide=function(){return this.toggle(!1)};y.prototype.show=function(){return this.toggle(!0)}; -function sa(a,b){return!b||!v.call(b,function(b){return 0>a.indexOf(b)})}var U={focus:"focusin",blur:"focusout"},ta={mouseenter:"mouseover",mouseleave:"mouseout"},ua=/^(?:mouse|pointer|contextmenu|drag|drop|click|dblclick)/i;function va(a,b,c,d,f){f.guid=f.guid||C.guid++;var h=a.__cashEvents=a.__cashEvents||{};h[b]=h[b]||[];h[b].push([c,d,f]);a.addEventListener(b,f)}function V(a){a=a.split(".");return[a[0],a.slice(1).sort()]} -function W(a,b,c,d,f){var h=a.__cashEvents=a.__cashEvents||{};if(b)h[b]&&(h[b]=h[b].filter(function(h){var p=h[0],ya=h[1];h=h[2];if(f&&h.guid!==f.guid||!sa(p,c)||d&&d!==ya)return!0;a.removeEventListener(b,h)}));else{for(b in h)W(a,b,c,d,f);delete a.__cashEvents}}y.prototype.off=function(a,b,c){var d=this;void 0===a?this.each(function(a,b){return W(b)}):(B(b)&&(c=b,b=""),E(N(a),function(a,h){a=V(ta[h]||U[h]||h);var f=a[0],w=a[1];d.each(function(a,d){return W(d,f,w,b,c)})}));return this}; -y.prototype.on=function(a,b,c,d){var f=this;if(!z(a)){for(var h in a)this.on(h,b,a[h]);return this}B(b)&&(c=b,b="");E(N(a),function(a,h){a=V(ta[h]||U[h]||h);var p=a[0],w=a[1];f.each(function(a,h){a=function za(a){if(!a.namespace||sa(w,a.namespace.split("."))){var f=h;if(b){for(var t=a.target;!G(t,b);){if(t===h)return;t=t.parentNode;if(!t)return}f=t;a.__delegate=!0}a.__delegate&&Object.defineProperty(a,"currentTarget",{configurable:!0,get:function(){return f}});t=c.call(f,a,a.data);d&&W(h,p,w,b,za); -!1===t&&(a.preventDefault(),a.stopPropagation())}};a.guid=c.guid=c.guid||C.guid++;va(h,p,w,b,a)})});return this};y.prototype.one=function(a,b,c){return this.on(a,b,c,!0)};y.prototype.ready=function(a){function b(){return a(C)}"loading"!==e.readyState?setTimeout(b):e.addEventListener("DOMContentLoaded",b);return this}; -y.prototype.trigger=function(a,b){if(z(a)){var c=V(a);a=c[0];c=c[1];var d=ua.test(a)?"MouseEvents":"HTMLEvents";var f=e.createEvent(d);f.initEvent(a,!0,!0);f.namespace=c.join(".")}else f=a;f.data=b;var h=f.type in U;return this.each(function(a,b){if(h&&B(b[f.type]))b[f.type]();else b.dispatchEvent(f)})};function wa(a){return a.multiple?H(m.call(a.options,function(a){return a.selected&&!a.disabled&&!a.parentNode.disabled}),"value"):a.value||""} -var xa=/%20/g,Aa=/file|reset|submit|button|image/i,Ba=/radio|checkbox/i;y.prototype.serialize=function(){var a="";this.each(function(b,c){E(c.elements||[c],function(b,c){c.disabled||!c.name||"FIELDSET"===c.tagName||Aa.test(c.type)||Ba.test(c.type)&&!c.checked||(b=wa(c),void 0!==b&&(b=K(b)?b:[b],E(b,function(b,d){b=a;d="&"+encodeURIComponent(c.name)+"="+encodeURIComponent(d).replace(xa,"+");a=b+d})))})});return a.substr(1)}; -y.prototype.val=function(a){return void 0===a?this[0]&&wa(this[0]):this.each(function(b,c){if("SELECT"===c.tagName){var d=K(a)?a:null===a?[]:[a];E(c.options,function(a,b){b.selected=0<=d.indexOf(b.value)})}else c.value=null===a?"":a})};y.prototype.clone=function(){return this.map(function(a,b){return b.cloneNode(!0)})};y.prototype.detach=function(){return this.each(function(a,b){b.parentNode&&b.parentNode.removeChild(b)})};var Ca=/^\s*<(\w+)[^>]*>/,Da=/^\s*<(\w+)\s*\/?>(?:<\/\1>)?\s*$/,X; -function A(a){if(!X){var b=e.createElement("table"),c=e.createElement("tr");X={"*":k,tr:e.createElement("tbody"),td:c,th:c,thead:b,tbody:b,tfoot:b}}if(!z(a))return[];if(Da.test(a))return[e.createElement(RegExp.$1)];b=Ca.test(a)&&RegExp.$1;b=X[b]||X["*"];b.innerHTML=a;return C(b.childNodes).detach().get()}C.parseHTML=A;y.prototype.empty=function(){return this.each(function(a,b){for(;b.firstChild;)b.removeChild(b.firstChild)})}; -y.prototype.html=function(a){return void 0===a?this[0]&&this[0].innerHTML:this.each(function(b,c){c.innerHTML=a})};y.prototype.remove=function(){return this.detach().off()};y.prototype.text=function(a){return void 0===a?this[0]?this[0].textContent:"":this.each(function(b,c){c.textContent=a})};y.prototype.unwrap=function(){this.parent().each(function(a,b){a=C(b);a.replaceWith(a.children())});return this};var Ea=e.documentElement; -y.prototype.offset=function(){var a=this[0];if(a)return a=a.getBoundingClientRect(),{top:a.top+g.pageYOffset-Ea.clientTop,left:a.left+g.pageXOffset-Ea.clientLeft}};y.prototype.offsetParent=function(){return C(this[0]&&this[0].offsetParent)};y.prototype.position=function(){var a=this[0];if(a)return{left:a.offsetLeft,top:a.offsetTop}};y.prototype.children=function(a){var b=[];this.each(function(a,d){q.apply(b,d.children)});return M(C(O(b)),a)}; -y.prototype.contents=function(){var a=[];this.each(function(b,c){q.apply(a,"IFRAME"===c.tagName?[c.contentDocument]:c.childNodes)});return C(O(a))};y.prototype.find=function(a){for(var b=[],c=0,d=this.length;c\s*$/g; -function Y(a){a=C(a);a.filter("script").add(a.find("script")).each(function(a,c){!c.src&&Fa.test(c.type)&&c.ownerDocument.documentElement.contains(c)&&eval(c.textContent.replace(Ga,""))})}function Z(a,b,c){E(a,function(a,f){E(b,function(b,d){b=a?d.cloneNode(!0):d;c?f.insertBefore(b,c&&f.firstChild):f.appendChild(b);Y(b)})})}y.prototype.append=function(){var a=this;E(arguments,function(b,c){Z(a,C(c))});return this};y.prototype.appendTo=function(a){Z(C(a),this);return this}; -y.prototype.insertAfter=function(a){var b=this;C(a).each(function(a,d){var c=d.parentNode;c&&b.each(function(b,f){b=a?f.cloneNode(!0):f;c.insertBefore(b,d.nextSibling);Y(b)})});return this};y.prototype.after=function(){var a=this;E(r.apply(arguments),function(b,c){r.apply(C(c).slice()).insertAfter(a)});return this};y.prototype.insertBefore=function(a){var b=this;C(a).each(function(a,d){var c=d.parentNode;c&&b.each(function(b,f){b=a?f.cloneNode(!0):f;c.insertBefore(b,d);Y(b)})});return this}; -y.prototype.before=function(){var a=this;E(arguments,function(b,c){C(c).insertBefore(a)});return this};y.prototype.prepend=function(){var a=this;E(arguments,function(b,c){Z(a,C(c),!0)});return this};y.prototype.prependTo=function(a){Z(C(a),r.apply(this.slice()),!0);return this};y.prototype.replaceWith=function(a){return this.before(a).remove()};y.prototype.replaceAll=function(a){C(a).replaceWith(this);return this}; -y.prototype.wrapAll=function(a){if(this[0]){a=C(a);this.first().before(a);for(a=a[0];a.children.length;)a=a.firstElementChild;this.appendTo(a)}return this};y.prototype.wrap=function(a){return this.each(function(b,c){var d=C(a)[0];C(c).wrapAll(b?d.cloneNode(!0):d)})};y.prototype.wrapInner=function(a){return this.each(function(b,c){b=C(c);c=b.contents();c.length?c.wrapAll(a):b.append(a)})}; -y.prototype.has=function(a){var b=z(a)?function(b,d){return!!x(a,d).length}:function(b,d){return d.contains(a)};return this.filter(b)};y.prototype.is=function(a){if(!a||!this[0])return!1;var b=L(a),c=!1;this.each(function(a,f){c=b.call(f,a,f);return!c});return c};y.prototype.next=function(a,b){return M(C(O(H(this,"nextElementSibling",b))),a)};y.prototype.nextAll=function(a){return this.next(a,!0)}; -y.prototype.not=function(a){if(!a||!this[0])return this;var b=L(a);return this.filter(function(a,d){return!b.call(d,a,d)})};y.prototype.parent=function(a){return M(C(O(H(this,"parentNode"))),a)};y.prototype.index=function(a){var b=a?C(a)[0]:this[0];a=a?this:C(b).parent().children();return n.call(a,b)};y.prototype.closest=function(a){if(!a||!this[0])return C();var b=this.filter(a);return b.length?b:this.parent().closest(a)}; -y.prototype.parents=function(a){return M(C(O(H(this,"parentElement",!0))),a)};y.prototype.prev=function(a,b){return M(C(O(H(this,"previousElementSibling",b))),a)};y.prototype.prevAll=function(a){return this.prev(a,!0)};y.prototype.siblings=function(a){var b=[];this.each(function(a,d){q.apply(b,C(d).parent().children(function(a,b){return b!==d}))});return M(C(O(b)),a)};"undefined"!==typeof exports?module.exports=C:g.cash=g.$=C; +'use strict';var e={"class":"className",contenteditable:"contentEditable","for":"htmlFor",readonly:"readOnly",maxlength:"maxLength",tabindex:"tabIndex",colspan:"colSpan",rowspan:"rowSpan",usemap:"useMap"};function g(a,b){try{return a(b)}catch(c){return b}} +var m=document,n=window,p=m.documentElement,r=m.createElement.bind(m),aa=r("div"),t=r("table"),ba=r("tbody"),ca=r("tr"),u=Array.isArray,v=Array.prototype,da=v.concat,w=v.filter,ea=v.indexOf,fa=v.map,ha=v.push,ia=v.slice,x=v.some,ja=v.splice,ka=/^#[\w-]*$/,la=/^\.[\w-]*$/,ma=/<.+>/,na=/^\w+$/;function y(a,b){return a&&(A(b)||B(b))?la.test(a)?b.getElementsByClassName(a.slice(1)):na.test(a)?b.getElementsByTagName(a):b.querySelectorAll(a):[]} +var C=function(){function a(a,c){if(a){if(a instanceof C)return a;var b=a;if(D(a)){if(b=(c instanceof C?c[0]:c)||m,b=ka.test(a)?b.getElementById(a.slice(1)):ma.test(a)?oa(a):y(a,b),!b)return}else if(E(a))return this.ready(a);if(b.nodeType||b===n)b=[b];this.length=b.length;a=0;for(c=this.length;aarguments.length?this[0]&&this[0][a]:this.each(function(c,h){h[a]=b});for(var c in a)this.prop(c,a[c]);return this}};F.get=function(a){if(void 0===a)return ia.call(this);a=Number(a);return this[0>a?a+this.length:a]};F.eq=function(a){return G(this.get(a))}; +F.first=function(){return this.eq(0)};F.last=function(){return this.eq(-1)};function L(a){return D(a)?function(b,c){return qa(c,a)}:E(a)?a:a instanceof C?function(b,c){return a.is(c)}:a?function(b,c){return c===a}:function(){return!1}}F.filter=function(a){var b=L(a);return G(w.call(this,function(a,d){return b.call(a,d,a)}))};function M(a,b){return b?a.filter(b):a}var sa=/\S+/g;function N(a){return D(a)?a.match(sa)||[]:[]}F.hasClass=function(a){return!!a&&x.call(this,function(b){return B(b)&&b.classList.contains(a)})}; +F.removeAttr=function(a){var b=N(a);return this.each(function(a,d){B(d)&&I(b,function(a,b){d.removeAttribute(b)})})};F.attr=function(a,b){if(a){if(D(a)){if(2>arguments.length){if(!this[0]||!B(this[0]))return;var c=this[0].getAttribute(a);return null===c?void 0:c}return void 0===b?this:null===b?this.removeAttr(a):this.each(function(c,h){B(h)&&h.setAttribute(a,b)})}for(c in a)this.attr(c,a[c]);return this}}; +F.toggleClass=function(a,b){var c=N(a),d=void 0!==b;return this.each(function(a,f){B(f)&&I(c,function(a,c){d?b?f.classList.add(c):f.classList.remove(c):f.classList.toggle(c)})})};F.addClass=function(a){return this.toggleClass(a,!0)};F.removeClass=function(a){return arguments.length?this.toggleClass(a,!1):this.attr("class","")}; +function O(a,b,c,d){for(var h=[],f=E(b),k=d&&L(d),q=0,R=a.length;qarguments.length)return this[0]&&Q(this[0],a,c);if(!a)return this;b=xa(a,b,c);return this.each(function(d,f){B(f)&&(c?f.style.setProperty(a,b):f.style[a]=b)})}for(var d in a)this.css(d,a[d]);return this};var ya=/^\s+|\s+$/;function za(a,b){a=a.dataset[b]||a.dataset[H(b)];return ya.test(a)?a:g(JSON.parse,a)} +F.data=function(a,b){if(!a){if(!this[0])return;var c={},d;for(d in this[0].dataset)c[d]=za(this[0],d);return c}if(D(a))return 2>arguments.length?this[0]&&za(this[0],a):void 0===b?this:this.each(function(c,d){c=b;c=g(JSON.stringify,c);d.dataset[H(a)]=c});for(d in a)this.data(d,a[d]);return this};function Aa(a,b){var c=a.documentElement;return Math.max(a.body["scroll"+b],c["scroll"+b],a.body["offset"+b],c["offset"+b],c["client"+b])} +function Ba(a,b){return S(a,"border"+(b?"Left":"Top")+"Width")+S(a,"padding"+(b?"Left":"Top"))+S(a,"padding"+(b?"Right":"Bottom"))+S(a,"border"+(b?"Right":"Bottom")+"Width")} +I([!0,!1],function(a,b){I(["Width","Height"],function(a,d){F[(b?"outer":"inner")+d]=function(c){if(this[0])return K(this[0])?b?this[0]["inner"+d]:this[0].document.documentElement["client"+d]:A(this[0])?Aa(this[0],d):this[0][(b?"offset":"client")+d]+(c&&b?S(this[0],"margin"+(a?"Top":"Left"))+S(this[0],"margin"+(a?"Bottom":"Right")):0)}})}); +I(["Width","Height"],function(a,b){var c=b.toLowerCase();F[c]=function(d){if(!this[0])return void 0===d?void 0:this;if(!arguments.length)return K(this[0])?this[0].document.documentElement["client"+b]:A(this[0])?Aa(this[0],b):this[0].getBoundingClientRect()[c]-Ba(this[0],!a);var h=parseInt(d,10);return this.each(function(b,d){B(d)&&(b=Q(d,"boxSizing"),d.style[c]=xa(c,h+("border-box"===b?Ba(d,!a):0)))})}});var V={}; +F.toggle=function(a){return this.each(function(b,c){if(B(c))if(void 0===a?"none"===Q(c,"display"):a){if(c.style.display=c.___cd||"","none"===Q(c,"display")){b=c.style;c=c.tagName;if(V[c])c=V[c];else{var d=r(c);m.body.insertBefore(d,null);var h=Q(d,"display");m.body.removeChild(d);c=V[c]="none"!==h?h:"block"}b.display=c}}else c.___cd=Q(c,"display"),c.style.display="none"})};F.hide=function(){return this.toggle(!1)};F.show=function(){return this.toggle(!0)}; +function Ca(a,b){return!b||!x.call(b,function(b){return 0>a.indexOf(b)})}var W={focus:"focusin",blur:"focusout"},Da={mouseenter:"mouseover",mouseleave:"mouseout"},Ea=/^(mouse|pointer|contextmenu|drag|drop|click|dblclick)/i;function Fa(a,b,c,d,h){var f=a.___ce=a.___ce||{};f[b]=f[b]||[];f[b].push([c,d,h]);a.addEventListener(b,h)}function X(a){a=a.split(".");return[a[0],a.slice(1).sort()]} +function Y(a,b,c,d,h){var f=a.___ce=a.___ce||{};if(b)f[b]&&(f[b]=f[b].filter(function(f){var k=f[0],R=f[1];f=f[2];if(h&&f.guid!==h.guid||!Ca(k,c)||d&&d!==R)return!0;a.removeEventListener(b,f)}));else for(b in f)Y(a,b,c,d,h)} +F.off=function(a,b,c){var d=this;if(void 0===a)this.each(function(a,b){(B(b)||A(b)||K(b))&&Y(b)});else if(D(a))E(b)&&(c=b,b=""),I(N(a),function(a,h){a=X(Da[h]||W[h]||h);var f=a[0],k=a[1];d.each(function(a,d){(B(d)||A(d)||K(d))&&Y(d,f,k,b,c)})});else for(var h in a)this.off(h,a[h]);return this}; +F.on=function(a,b,c,d,h){var f=this;if(!D(a)){for(var k in a)this.on(k,b,c,a[k],h);return this}D(b)||(void 0!==b&&null!==b&&(void 0!==c&&(d=c),c=b),b="");E(d)||(d=c,c=void 0);if(!d)return this;I(N(a),function(a,k){a=X(Da[k]||W[k]||k);var l=a[0],q=a[1];l&&f.each(function(a,f){if(B(f)||A(f)||K(f))a=function Ja(a){if(!a.namespace||Ca(q,a.namespace.split("."))){var k=f;if(b){for(var z=a.target;!qa(z,b);){if(z===f)return;z=z.parentNode;if(!z)return}k=z;a.___cd=!0}a.___cd&&Object.defineProperty(a,"currentTarget", +{configurable:!0,get:function(){return k}});Object.defineProperty(a,"data",{configurable:!0,get:function(){return c}});z=d.call(k,a,a.___td);h&&Y(f,l,q,b,Ja);!1===z&&(a.preventDefault(),a.stopPropagation())}},a.guid=d.guid=d.guid||G.guid++,Fa(f,l,q,b,a)})});return this};F.one=function(a,b,c,d){return this.on(a,b,c,d,!0)};F.ready=function(a){function b(){return setTimeout(a,0,G)}"loading"!==m.readyState?b():m.addEventListener("DOMContentLoaded",b);return this}; +F.trigger=function(a,b){if(D(a)){var c=X(a),d=c[0];c=c[1];if(!d)return this;var h=Ea.test(d)?"MouseEvents":"HTMLEvents";a=m.createEvent(h);a.initEvent(d,!0,!0);a.namespace=c.join(".")}a.___td=b;var f=a.type in W;return this.each(function(b,c){if(f&&E(c[a.type]))c[a.type]();else c.dispatchEvent(a)})};function Ga(a){return a.multiple&&a.options?O(w.call(a.options,function(a){return a.selected&&!a.disabled&&!a.parentNode.disabled}),"value"):a.value||""} +var Ha=/%20/g,Ia=/\r?\n/g,Ka=/file|reset|submit|button|image/i,La=/radio|checkbox/i;F.serialize=function(){var a="";this.each(function(b,c){I(c.elements||[c],function(b,c){c.disabled||!c.name||"FIELDSET"===c.tagName||Ka.test(c.type)||La.test(c.type)&&!c.checked||(b=Ga(c),void 0!==b&&(b=u(b)?b:[b],I(b,function(b,d){b=a;d="&"+encodeURIComponent(c.name)+"="+encodeURIComponent(d.replace(Ia,"\r\n")).replace(Ha,"+");a=b+d})))})});return a.slice(1)}; +F.val=function(a){return arguments.length?this.each(function(b,c){if((b=c.multiple&&c.options)||La.test(c.type)){var d=u(a)?fa.call(a,String):null===a?[]:[String(a)];b?I(c.options,function(a,b){b.selected=0<=d.indexOf(b.value)},!0):c.checked=0<=d.indexOf(c.value)}else c.value=void 0===a||null===a?"":a}):this[0]&&Ga(this[0])};F.clone=function(){return this.map(function(a,b){return b.cloneNode(!0)})};F.detach=function(a){M(this,a).each(function(a,c){c.parentNode&&c.parentNode.removeChild(c)});return this}; +var Ma=/^\s*<(\w+)[^>]*>/,Na=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,Oa={"*":aa,tr:ba,td:ca,th:ca,thead:t,tbody:t,tfoot:t};function oa(a){if(!D(a))return[];if(Na.test(a))return[r(RegExp.$1)];var b=Ma.test(a)&&RegExp.$1;b=Oa[b]||Oa["*"];b.innerHTML=a;return G(b.childNodes).detach().get()}G.parseHTML=oa;F.empty=function(){return this.each(function(a,b){for(;b.firstChild;)b.removeChild(b.firstChild)})}; +F.html=function(a){return arguments.length?void 0===a?this:this.each(function(b,c){B(c)&&(c.innerHTML=a)}):this[0]&&this[0].innerHTML};F.remove=function(a){M(this,a).detach().off();return this};F.text=function(a){return void 0===a?this[0]?this[0].textContent:"":this.each(function(b,c){B(c)&&(c.textContent=a)})};F.unwrap=function(){this.parent().each(function(a,b){"BODY"!==b.tagName&&(a=G(b),a.replaceWith(a.children()))});return this}; +F.offset=function(){var a=this[0];if(a)return a=a.getBoundingClientRect(),{top:a.top+n.pageYOffset,left:a.left+n.pageXOffset}};F.offsetParent=function(){return this.map(function(a,b){for(a=b.offsetParent;a&&"static"===Q(a,"position");)a=a.offsetParent;return a||p})}; +F.position=function(){var a=this[0];if(a){var b="fixed"===Q(a,"position"),c=b?a.getBoundingClientRect():this.offset();if(!b){var d=a.ownerDocument;for(b=a.offsetParent||d.documentElement;(b===d.body||b===d.documentElement)&&"static"===Q(b,"position");)b=b.parentNode;b!==a&&B(b)&&(d=G(b).offset(),c.top-=d.top+S(b,"borderTopWidth"),c.left-=d.left+S(b,"borderLeftWidth"))}return{top:c.top-S(a,"marginTop"),left:c.left-S(a,"marginLeft")}}}; +F.children=function(a){return M(G(P(O(this,function(a){return a.children}))),a)};F.contents=function(){return G(P(O(this,function(a){return"IFRAME"===a.tagName?[a.contentDocument]:"TEMPLATE"===a.tagName?a.content.childNodes:a.childNodes})))};F.find=function(a){return G(P(O(this,function(b){return y(a,b)})))};var Pa=/^\s*\s*$/g,Qa=/^$|^module$|\/(java|ecma)script/i,Ra=["type","src","nonce","noModule"]; +function Sa(a,b){a=G(a);a.filter("script").add(a.find("script")).each(function(a,d){if(Qa.test(d.type)&&p.contains(d)){var c=r("script");c.text=d.textContent.replace(Pa,"");I(Ra,function(a,b){d[b]&&(c[b]=d[b])});b.head.insertBefore(c,null);b.head.removeChild(c)}})} +function Z(a,b,c,d,h,f,k,q){I(a,function(a,f){I(G(f),function(a,f){I(G(b),function(b,k){var l=c?k:f;b=c?a:b;k=c?f:k;l=b?l.cloneNode(!0):l;b=!b;h?k.insertBefore(l,d?k.firstChild:null):k.parentNode.insertBefore(l,d?k:k.nextSibling);b&&Sa(l,k.ownerDocument)},q)},k)},f);return b}F.after=function(){return Z(arguments,this,!1,!1,!1,!0,!0)};F.append=function(){return Z(arguments,this,!1,!1,!0)};F.appendTo=function(a){return Z(arguments,this,!0,!1,!0)};F.before=function(){return Z(arguments,this,!1,!0)}; +F.insertAfter=function(a){return Z(arguments,this,!0,!1,!1,!1,!1,!0)};F.insertBefore=function(a){return Z(arguments,this,!0,!0)};F.prepend=function(){return Z(arguments,this,!1,!0,!0,!0,!0)};F.prependTo=function(a){return Z(arguments,this,!0,!0,!0,!1,!1,!0)};F.replaceWith=function(a){return this.before(a).remove()};F.replaceAll=function(a){G(a).replaceWith(this);return this};F.wrapAll=function(a){a=G(a);for(var b=a[0];b.children.length;)b=b.firstElementChild;this.first().before(a);return this.appendTo(b)}; +F.wrap=function(a){return this.each(function(b,c){var d=G(a)[0];G(c).wrapAll(b?d.cloneNode(!0):d)})};F.wrapInner=function(a){return this.each(function(b,c){b=G(c);c=b.contents();c.length?c.wrapAll(a):b.append(a)})};F.has=function(a){var b=D(a)?function(b,d){return y(a,d).length}:function(b,d){return d.contains(a)};return this.filter(b)};F.is=function(a){var b=L(a);return x.call(this,function(a,d){return b.call(a,d,a)})};F.next=function(a,b,c){return M(G(P(O(this,"nextElementSibling",b,c))),a)}; +F.nextAll=function(a){return this.next(a,!0)};F.nextUntil=function(a,b){return this.next(b,!0,a)};F.not=function(a){var b=L(a);return this.filter(function(c,d){return(!D(a)||B(d))&&!b.call(d,c,d)})};F.parent=function(a){return M(G(P(O(this,"parentNode"))),a)};F.index=function(a){var b=a?G(a)[0]:this[0];a=a?this:G(b).parent().children();return ea.call(a,b)};F.closest=function(a){var b=this.filter(a);if(b.length)return b;var c=this.parent();return c.length?c.closest(a):b}; +F.parents=function(a,b){return M(G(P(O(this,"parentElement",!0,b))),a)};F.parentsUntil=function(a,b){return this.parents(b,a)};F.prev=function(a,b,c){return M(G(P(O(this,"previousElementSibling",b,c))),a)};F.prevAll=function(a){return this.prev(a,!0)};F.prevUntil=function(a,b){return this.prev(b,!0,a)};F.siblings=function(a){return M(G(P(O(this,function(a){return G(a).parent().children().not(a)}))),a)};"undefined"!==typeof exports?module.exports=G:n.cash=n.$=G; })(); \ No newline at end of file diff --git a/trilium-web-clipper.iml b/trilium-web-clipper.iml index 8021953ed..c3e779f97 100644 --- a/trilium-web-clipper.iml +++ b/trilium-web-clipper.iml @@ -2,7 +2,9 @@ - + + +