diff --git a/app.js b/app.js index a99b8a2..667a09d 100644 --- a/app.js +++ b/app.js @@ -12,54 +12,54 @@ const fakeServe = new nodeStatic.Server('fakeStatic/'); const server = https.createServer(); fs.readdir('/etc/letsencrypt/live', { withFileTypes: true }, (err, files) => { - if (!err) - files - .filter(file => file.isDirectory()) - .map(folder => folder.name) - .forEach(dir => { - server.addContext(dir, { - key: fs.readFileSync(`/etc/letsencrypt/live/${dir}/privkey.pem`), - cert: fs.readFileSync(`/etc/letsencrypt/live/${dir}/fullchain.pem`) - }); - }); + if (!err) + files + .filter(file => file.isDirectory()) + .map(folder => folder.name) + .forEach(dir => { + server.addContext(dir, { + key: fs.readFileSync(`/etc/letsencrypt/live/${dir}/privkey.pem`), + cert: fs.readFileSync(`/etc/letsencrypt/live/${dir}/fullchain.pem`) + }); + }); }); server.on('request', (request, response) => { - const ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress; + const ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress; - const isLS = ip.startsWith('34.216.110') || ip.startsWith('54.244.51') || ip.startsWith('54.172.60') || ip.startsWith('34.203.250') || ip.startsWith('34.203.254') || ['18.237.145.219', '34.213.241.18', '54.184.142.71', '34.219.54.89', '52.13.31.12', '52.89.157.185', '34.208.60.206', '3.80.101.141', '54.90.242.158', '54.172.185.65', '3.83.250.144', '18.209.180.25', '54.167.181.168', '54.166.136.197', '52.207.207.52', '54.252.242.153', '3.104.121.59', '34.253.198.121', '63.33.56.11', '34.250.114.219', '54.171.251.199'].includes(ip); + const isLS = ip.startsWith('34.216.110') || ip.startsWith('54.244.51') || ip.startsWith('54.172.60') || ip.startsWith('34.203.250') || ip.startsWith('34.203.254') || ['18.237.145.219', '34.213.241.18', '54.184.142.71', '34.219.54.89', '52.13.31.12', '52.89.157.185', '34.208.60.206', '3.80.101.141', '54.90.242.158', '54.172.185.65', '3.83.250.144', '18.209.180.25', '54.167.181.168', '54.166.136.197', '52.207.207.52', '54.252.242.153', '3.104.121.59', '34.253.198.121', '63.33.56.11', '34.250.114.219', '54.171.251.199'].includes(ip); - const unlockNow = request.url === '/?unlock'; - if (unlockNow) - response.setHeader('Set-Cookie', ['key=standard; expires=Sun, 1 Jan 2023 00:00:00 UTC; path=/']); - const unlockPatronNow = request.url === '/?unlockPatron'; - if (unlockPatronNow) - response.setHeader('Set-Cookie', ['key=patron; expires=Sun, 1 Jan 2023 00:00:00 UTC; path=/']); + const unlockNow = request.url === '/?unlock'; + if (unlockNow) + response.setHeader('Set-Cookie', ['key=standard; expires=Sun, 1 Jan 2023 00:00:00 UTC; path=/']); + const unlockPatronNow = request.url === '/?unlockPatron'; + if (unlockPatronNow) + response.setHeader('Set-Cookie', ['key=patron; expires=Sun, 1 Jan 2023 00:00:00 UTC; path=/']); - const unlocked = request.headers['cookie'] === 'key=standard' || unlockNow; - const patronUnlocked = request.headers['cookie'] === 'key=patron' || unlockPatronNow; + const unlocked = request.headers['cookie'] === 'key=standard' || unlockNow; + const patronUnlocked = request.headers['cookie'] === 'key=patron' || unlockPatronNow; - if (bare.route_request(request, response)) - return true; + if (bare.route_request(request, response)) + return true; - if (!(unlocked || patronUnlocked) && (isLS || request.headers.host === 'nebulaproxy.nebula.bio' && !request.headers['user-agent'].match(/CrOS/))) - fakeServe.serve(request, response); - else { - if (bare.route_request(request, response)) - return true; - - if (patronUnlocked) - patronServe.serve(request, response); - else - serve.serve(request, response); - } + if (!(unlocked || patronUnlocked) && (isLS || request.headers.host === 'nebulaproxy.nebula.bio' && !request.headers['user-agent'].match(/CrOS/))) + fakeServe.serve(request, response); + else { + if (bare.route_request(request, response)) + return true; + + if (patronUnlocked) + patronServe.serve(request, response); + else + serve.serve(request, response); + } }); server.on('upgrade', (req, socket, head) => { - if (bare.route_upgrade(req, socket, head)) - return; + if (bare.route_upgrade(req, socket, head)) + return; - socket.end(); + socket.end(); }); -server.listen(443); +server.listen(443); \ No newline at end of file diff --git a/static/images/cur.gif b/static/images/cur.gif new file mode 100644 index 0000000..e9fd26a Binary files /dev/null and b/static/images/cur.gif differ diff --git a/static/images/cursor.cur b/static/images/cursor.cur new file mode 100644 index 0000000..4817c82 Binary files /dev/null and b/static/images/cursor.cur differ diff --git a/static/images/logo.png b/static/images/logo.png new file mode 100644 index 0000000..3afb9bf Binary files /dev/null and b/static/images/logo.png differ diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..8c792ed --- /dev/null +++ b/static/index.html @@ -0,0 +1,65 @@ + + + + + Nebula + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +

© Nebula Services. All rights reserved.

+ + + + + + \ No newline at end of file diff --git a/static/mobile/.DS_Store b/static/mobile/.DS_Store new file mode 100644 index 0000000..3fd539b Binary files /dev/null and b/static/mobile/.DS_Store differ diff --git a/static/mobile/index.html b/static/mobile/index.html new file mode 100644 index 0000000..00f4847 --- /dev/null +++ b/static/mobile/index.html @@ -0,0 +1,49 @@ + + + + + Nebula + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+

© Nebula Services. All rights reserved. |

+ + + + + + \ No newline at end of file diff --git a/static/mobile/resources/deviceHandler.js b/static/mobile/resources/deviceHandler.js new file mode 100644 index 0000000..0d0ec91 --- /dev/null +++ b/static/mobile/resources/deviceHandler.js @@ -0,0 +1 @@ +(function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))window.location=b})(navigator.userAgent||navigator.vendor||window.opera,'/mobile'); \ No newline at end of file diff --git a/static/mobile/resources/form.js b/static/mobile/resources/form.js new file mode 100644 index 0000000..8069c4e --- /dev/null +++ b/static/mobile/resources/form.js @@ -0,0 +1,160 @@ +var option = localStorage.getItem('nogg'); +var nogg = document.getElementById('nogg'); + +function toggleNoGG() { + console.log(option); + if (option === 'on') { + nogg.style.color = ''; + option = 'off'; + localStorage.setItem('nogg', 'off'); + } else { + nogg.style.color = 'green'; + option = 'on'; + localStorage.setItem('nogg', 'on'); + } +} + +window.addEventListener('load', () => { + if (localStorage.getItem('nogg') === 'on') + nogg.style.color = 'green'; + + function isUrl(val = '') { + if (/^http(s?):\/\//.test(val) || val.includes('.') && val.substr(0, 1) !== ' ') return true; + return false; + }; + + // NOGG + const useNoGG = false; + const form = document.querySelector('form'); + form.addEventListener('submit', event => { + event.preventDefault(); + + if (typeof navigator.serviceWorker === 'undefined') + alert('Your browser does not support service workers or you are in private browsing!'); + console.log("Your Browser does not support ServiceWorkers and responded Undefined.") + + navigator.serviceWorker.register('./sw.js', { + scope: __uv$config.prefix + }).then(() => { + const value = event.target.firstElementChild.value; + + let url = value.trim(); + if (!isUrl(url)) + url = 'https://www.google.com/search?q=' + url; + else + if (!(url.startsWith('https://') || url.startsWith('http://'))) url = 'http://' + url; + const redirectTo = __uv$config.prefix + __uv$config.encodeUrl(url); + const option = localStorage.getItem('nogg'); + if (option === 'on') { + const nogg = window.open("about:blank", '_self', "popup"); + + setTimeout(() => { + nogg.document.write(` + + + + Google Classroom + + + + + + + + `); + }, 500); + } else location.href = redirectTo; + }); + }); +}); + +function hide() { + var x = document.getElementById("banner_bg_main"); + if (x.style.display === "none") { + x.style.display = "block"; + } else { + x.style.display = "none"; + } +} + +var autoFocusElem = document.getElementById("url"); +setTimeout(() => { autoFocusElem.autofocus = true }, 500); \ No newline at end of file diff --git a/static/mobile/style/main.css b/static/mobile/style/main.css new file mode 100644 index 0000000..4cb7e13 --- /dev/null +++ b/static/mobile/style/main.css @@ -0,0 +1,197 @@ +:root { + --background-primary: #191724; + --navbar-color: #26233a; + --navbar-height: 4em; + --navbar-text-color: #e0def4; + --input-text-color: #e0def4; + --input-placeholder-color: #6e6a86; + --input-background-color: #1f1d2e; + --input-border-color: #eb6f92; + --input-border-size: 0.1em; +} + + ::-webkit-input-placeholder { + text-align: center; + font-family: 'Roboto'; +} + + :-moz-placeholder { + text-align: center; +} + +#navbar { + height: 60px; + text-align: center; + align-items: center; + display: flex; + position: fixed; + top: 0; + left: 0; + right: 0; + background-color: var(--navbar-color); +} + +a { + color: white; + text-decoration: none !important; + font-family: 'Roboto'; +} + +a:hover { + color: grey; + transition: 0.5s; + cursor: pointer; +} + +.down { + background-color: rgb(90, 24, 154); + left: inherit !important; + font-family: 'Helvetica'; + background-color: var(--navbar-color); + /* box-shadow: 2px 2px rgb(0 0 0 / 20%); */ + color: white; + display: none; + visibility: hidden; + opacity: 0; + list-style-type: none; + position: fixed; + border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; + list-style-type: none; +} + +#navbar ul:not(.down) { + font-family: 'Helvetica'; + background-color: var(--navbar-color); + /* box-shadow: 2px 2px rgb(0 0 0 / 20%); */ + color: white; + margin-left: auto; + list-style-type: none; + float: right !important; + margin-right: 5%; +} + +#navbar ul li { + float: left; + padding-top: 1em; + padding-bottom: 1em; + padding-right: 1em; + padding-left: 1em; + padding: 1rem; +} + + ::placeholder, +input[type='text'] { + color: white; + font-size: 20px; + text-align: center; + font-family: 'Roboto'; +} + +#navbar ul p, +ul a { + font-weight: bold; +} + +*/ +/* + #navbar ul li p, ul li a { + font-weight: normal; + } + */ + +#navbar ul li ul { + border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; + visibility: hidden; + opacity: 0; + margin-top: 1rem; + left: 0; + display: none; +} + +#navbar ul li:hover ul, +ul li ul:hover { + visibility: visible; + opacity: 1; + display: block; +} + +#navbar ul li p { + color: white; + font-family: 'Calibri'; + z-index: 3 !important; +} + +#navbar ul li ul li { + clear: both; + width: 100%; +} + +#content { + display: flex; + justify-content: center; + align-items: center; + height: 98%; + color: white; + flex-direction: column; + font-family: 'Roboto'; +} + +#content h1 { + padding-bottom: 0.5em; + font-weight: 100; + text-align: center; +} + +#content img { + padding-left: .5em; + filter: brightness(0) invert(1); +} + +#content input { + font-size: 20px; + text-align: center; + font-family: 'Calibri'; + border-style: solid !important; + border: 1.3px solid var(--input-border-color); + border-width: 1px; + border-radius: 15px; + background-color: var(--input-background-color); + color: var(--input-text-color); + width: 300px; + height: 50px; + box-shadow: none !important; + outline: none; + color: white; + text-align: center; + font-family: 'Roboto'; + animation-name: inputwide; + animation-duration: 2s; +} + + +/* + --input-text-color: #e0def4; + --input-placeholder-color: #6e6a86; + --input-background-color: #1f1d2e; + --input-border-color: #eb6f92; + --input-border-size: 0.1em; + */ + +#content input:focus { + /* outline: 1.3px solid #eb6f9; !important;*/ + outline: none; + box-shadow: none !important; +} + +@keyframes inputwide { + 0% { + width: 0px; + transition-duration: 0.5s; + } + 100% { + width: 300px; + transition-duration: 0.5s; + } +} \ No newline at end of file diff --git a/static/mobile/style/master.css b/static/mobile/style/master.css new file mode 100644 index 0000000..8aef670 --- /dev/null +++ b/static/mobile/style/master.css @@ -0,0 +1,72 @@ +@import url("https://fonts.googleapis.com/css2?family=Dongle&family=Roboto:wght@100&display=swap"); +:root { + --background-primary: #191724; + --text-color-primary: #31748f; + --text-color-secondary: #9ccfd8; + --header-color: #26233a; + --header-height: 4em; + --header-text-color: #e0def4; + --input-text-color: white; + --input-placeholder-color: #6e6a86; + --input-background-color: #1f1d2e; + --input-border-color: #eb6f92; + --input-border-size: 0.1em; +} + +*, +*::before, +*::after { + padding: 0; + margin: 0; + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; + height: 100%; +} + +body { + background-color: var(--background-primary); + color: var(--text-color-primary); + animation: fadeInAnimation ease 3s; + animation-iteration-count: 1; + animation-fill-mode: forwards; +} + +@keyframes fadeInAnimation { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +input:focus::placeholder { + color: transparent; +} + +#navbar #thumbImg { + transition: width 2s, height 2s, transform 2s; +} + +#navbar #thumbImg:hover { + transform: rotate(360deg); +} + +@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@1,100&display=swap'); +.stamp { + text-align: left; + position: fixed; + bottom: 0; + font-family: 'Montserrat', sans-serif; + font-style: italic; + font-weight: lighter; + color: whitesmoke; + opacity: 38%; + user-select: none; + font-size: 13px; +} \ No newline at end of file diff --git a/static/mobile/style/options.css b/static/mobile/style/options.css new file mode 100644 index 0000000..3ee17d2 --- /dev/null +++ b/static/mobile/style/options.css @@ -0,0 +1,230 @@ +@import url("https://fonts.googleapis.com/css2?family=Work+Sans:wght@300&display=swap"); +:root { + --background-primary: #191724; + --sidebar-color: #191724; + --sidebar-text-color: #e0def4; + --text-color-primary: #e0def4; + --text-color-secondary: #6e6a86; + --focus-color: #eb6f92; + --header-height: 10vh; + --section-font-size: 20pt; + --section-font: 'Calibri'; + --section-padding: 0.5em; + --setting-distance-from-sidebar: 1em; + --setting-distance-from-right: 1em; + --setting-name-font: 'Calibri'; + --setting-desc-font: 'Calibri'; +} + + +/* +body { + background-color: var(--background-primary); +}*/ + +#sidebar { + animation: fadeIn 750ms ease-in 300ms forwards; + -webkit-animation: fadeIn 750ms ease-in 300ms forwards; + position: absolute; + top: var(--header-height); + left: 0; + background-color: var(--sidebar-color); + transition: width 0.5s; + width: var(--sidebar-width); +} + +.setting li a { + background-color: #2e2828; + padding: 10px 16px; + border-radius: 5px; +} + +.settings-div li a ul { + border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; + visibility: hidden; + opacity: 0; + margin-top: 10px; + left: 0 !important; + display: none; +} + +.settings-div li a:hover ul, +ul li:hover { + visibility: visible; + opacity: 1; + display: block; +} + + +/* +.settings-div ul li p{ + color: white; + font-family: 'Calibri'; + z-index: 3 !important; + +}*/ + +li { + list-style-type: none; +} + +.settings-div li a ul li { + clear: both; + width: 100%; +} + +.section { + display: flex; + align-items: center; + flex-direction: column; + background-color: transparent; + color: var(--sidebar-text-color); + font-size: var(--section-font-size); + font-family: var(--section-font); + width: 100%; + transition: background-color 0.5s; + padding-top: var(--section-padding); + padding-bottom: var(--section-padding); +} + +.section:hover { + background-color: #ffffff20; +} + +.settings-div { + position: absolute; + left: calc(var(--sidebar-width) + var(--setting-distance-from-sidebar)); + top: 0; + width: calc(100vw - var(--sidebar-width) - var(--setting-distance-from-sidebar)); + padding-top: 5%; +} + +.name { + color: var(--text-color-primary); + font-size: 2vmax; + margin: 0; + font-family: var(--setting-name-font); +} + +.description { + color: var(--text-color-secondary); + margin: 0; + font-size: 2vmax; + font-family: var(--setting-desc-font); +} + +.setting-input { + /* left: 100%; */ + color: black !important; + position: relative; + /* right: 0; */ + transform: translateY(-1.5em); + float: right; + margin-right: 5%; +} + +ul li { + float: left; + padding-top: 1em; + padding-bottom: 1em; + padding-right: 1em; + padding-left: 1em; + padding: 1rem; +} + +.button { + width: 30px; + height: 30px; + transform: translateY(-30px); + justify-self: end; + font-family: var(--setting-desc-font); + align-self: flex-end; + color: white; +} + +@-webkit-keyframes fadeIn { + 0% { + opacity: 0.01; + } + 100% { + opacity: 1; + } +} + +@keyframes fadeIn { + 0% { + opacity: 0.01; + } + 100% { + opacity: 1; + } +} + +.container { + display: flex; + height: 100%; + justify-content: left; + align-items: left; +} + +.rectangle { + display: flex; + align-items: center; + justify-content: flex-start; + position: relative; + width: 50px; + margin-left: auto; + margin-top: auto; + height: 50px; + background: #380848; + transform: scale(0); + border-radius: 50%; + color: white; + opacity: 0; + overflow: hidden; + animation: scale-in 0.3s ease-out forwards, expand 0.35s 0.25s ease-out forwards; +} + +.notification-text { + display: flex; + align-items: center; + padding: 0 16px; + font-family: 'Roboto', sans-serif; + font-size: 14px; + animation: fade-in 0.65s ease-in forwards; +} + +@keyframes scale-in { + 100% { + transform: scale(1); + opacity: 1; + } +} + +@keyframes expand { + 50% { + width: 350px; + border-radius: 6px; + } + 100% { + width: 300px; + border-radius: 4px; + box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, .2), 0px 1px 1px 0px rgba(0, 0, 0, .14), 0px 3px 3px -1px rgba(0, 0, 0, .12); + } +} + +@keyframes fade-in { + 0% { + opacity: 0; + } + 100% { + opacity: 0.8; + } +} + +.stamp { + text-align: left; + position: fixed; + bottom: 0; +} \ No newline at end of file diff --git a/static/mobile/sw.js b/static/mobile/sw.js new file mode 100644 index 0000000..89ac6a7 --- /dev/null +++ b/static/mobile/sw.js @@ -0,0 +1,5 @@ +importScripts('./uv/uv.sw.js'); + +const sw = new UVServiceWorker(); + +self.addEventListener('fetch', event => event.respondWith(sw.fetch(event))); \ No newline at end of file diff --git a/static/mobile/uv/uv.bundle.js b/static/mobile/uv/uv.bundle.js new file mode 100644 index 0000000..099a868 --- /dev/null +++ b/static/mobile/uv/uv.bundle.js @@ -0,0 +1,39304 @@ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ([ +/* 0 */, +/* 1 */ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _events_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); +/* harmony import */ var parse5__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3); + + + +class HTML extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] { + constructor(ctx) { + super(); + this.ctx = ctx; + this.rewriteUrl = ctx.rewriteUrl; + this.sourceUrl = ctx.sourceUrl; + }; + rewrite(str, options = {}) { + if (!str) return str; + return this.recast(str, node => { + if (node.tagName) this.emit('element', node, 'rewrite'); + if (node.attr) this.emit('attr', node, 'rewrite'); + if (node.nodeName === '#text') this.emit('text', node, 'rewrite'); + }, options) + }; + source(str, options = {}) { + if (!str) return str; + return this.recast(str, node => { + if (node.tagName) this.emit('element', node, 'source'); + if (node.attr) this.emit('attr', node, 'source'); + if (node.nodeName === '#text') this.emit('text', node, 'source'); + }, options) + }; + recast(str, fn, options = {}) { + try { + const ast = (options.document ? parse5__WEBPACK_IMPORTED_MODULE_1__.parse : parse5__WEBPACK_IMPORTED_MODULE_1__.parseFragment)(new String(str).toString()); + this.iterate(ast, fn, options); + return (0,parse5__WEBPACK_IMPORTED_MODULE_1__.serialize)(ast); + } catch(e) { + return str; + }; + }; + iterate(ast, fn, fnOptions) { + if (!ast) return ast; + + if (ast.tagName) { + const element = new P5Element(ast, false, fnOptions); + fn(element); + if (ast.attrs) { + for (const attr of ast.attrs) { + if (!attr.skip) fn(new AttributeEvent(element, attr, fnOptions)); + }; + }; + }; + + if (ast.childNodes) { + for (const child of ast.childNodes) { + if (!child.skip) this.iterate(child, fn, fnOptions); + }; + }; + + if (ast.nodeName === '#text') { + fn(new TextEvent(ast, new P5Element(ast.parentNode), false, fnOptions)); + }; + + return ast; + }; + wrapSrcset(str, meta = this.ctx.meta) { + return str.split(',').map(src => { + const parts = src.trimStart().split(' '); + if (parts[0]) parts[0] = this.ctx.rewriteUrl(parts[0], meta); + return parts.join(' '); + }).join(', '); + }; + unwrapSrcset(str, meta = this.ctx.meta) { + return str.split(',').map(src => { + const parts = src.trimStart().split(' '); + if (parts[0]) parts[0] = this.ctx.sourceUrl(parts[0], meta); + return parts.join(' '); + }).join(', '); + }; + static parse = parse5__WEBPACK_IMPORTED_MODULE_1__.parse; + static parseFragment = parse5__WEBPACK_IMPORTED_MODULE_1__.parseFragment; + static serialize = parse5__WEBPACK_IMPORTED_MODULE_1__.serialize; +}; + +class P5Element extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] { + constructor(node, stream = false, options = {}) { + super(); + this.stream = stream; + this.node = node; + this.options = options; + }; + setAttribute(name, value) { + for (const attr of this.attrs) { + if (attr.name === name) { + attr.value = value; + return true; + }; + }; + + this.attrs.push( + { + name, + value, + } + ); + }; + getAttribute(name) { + const attr = this.attrs.find(attr => attr.name === name) || {}; + return attr.value; + }; + hasAttribute(name) { + return !!this.attrs.find(attr => attr.name === name); + }; + removeAttribute(name) { + const i = this.attrs.findIndex(attr => attr.name === name); + if (typeof i !== 'undefined') this.attrs.splice(i, 1); + }; + get tagName() { + return this.node.tagName; + }; + set tagName(val) { + this.node.tagName = val; + }; + get childNodes() { + return !this.stream ? this.node.childNodes : null; + }; + get innerHTML() { + return !this.stream ? (0,parse5__WEBPACK_IMPORTED_MODULE_1__.serialize)( + { + nodeName: '#document-fragment', + childNodes: this.childNodes, + } + ) : null; + }; + set innerHTML(val) { + if (!this.stream) this.node.childNodes = (0,parse5__WEBPACK_IMPORTED_MODULE_1__.parseFragment)(val).childNodes; + }; + get outerHTML() { + return !this.stream ? (0,parse5__WEBPACK_IMPORTED_MODULE_1__.serialize)( + { + nodeName: '#document-fragment', + childNodes: [ this ], + } + ) : null; + }; + set outerHTML(val) { + if (!this.stream) this.parentNode.childNodes.splice(this.parentNode.childNodes.findIndex(node => node === this.node), 1, ...(0,parse5__WEBPACK_IMPORTED_MODULE_1__.parseFragment)(val).childNodes); + }; + get textContent() { + if (this.stream) return null; + + let str = ''; + iterate(this.node, node => { + if (node.nodeName === '#text') str += node.value; + }); + + return str; + }; + set textContent(val) { + if (!this.stream) this.node.childNodes = [ + { + nodeName: '#text', + value: val, + parentNode: this.node + } + ]; + }; + get nodeName() { + return this.node.nodeName; + } + get parentNode() { + return this.node.parentNode ? new P5Element(this.node.parentNode) : null; + }; + get attrs() { + return this.node.attrs; + } + get namespaceURI() { + return this.node.namespaceURI; + } +}; + +class AttributeEvent { + constructor(node, attr, options = {}) { + this.attr = attr; + this.attrs = node.attrs; + this.node = node; + this.options = options; + }; + delete() { + const i = this.attrs.findIndex(attr => attr === this.attr); + + this.attrs.splice(i, 1); + + Object.defineProperty(this, 'deleted', { + get: () => true, + }); + + return true; + }; + get name() { + return this.attr.name; + }; + + set name(val) { + this.attr.name = val; + }; + get value() { + return this.attr.value; + }; + + set value(val) { + this.attr.value = val; + }; + get deleted() { + return false; + }; +}; + +class TextEvent { + constructor(node, element, stream = false, options = {}) { + this.stream = stream; + this.node = node; + this.element = element; + this.options = options; + }; + get nodeName() { + return this.node.nodeName; + } + get parentNode() { + return this.element; + }; + get value() { + return this.stream ? this.node.text : this.node.value; + }; + set value(val) { + + if (this.stream) this.node.text = val; + else this.node.value = val; + }; +}; + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (HTML); + +/***/ }), +/* 2 */ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +var R = typeof Reflect === 'object' ? Reflect : null +var ReflectApply = R && typeof R.apply === 'function' + ? R.apply + : function ReflectApply(target, receiver, args) { + return Function.prototype.apply.call(target, receiver, args); + } + +var ReflectOwnKeys +if (R && typeof R.ownKeys === 'function') { + ReflectOwnKeys = R.ownKeys +} else if (Object.getOwnPropertySymbols) { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target) + .concat(Object.getOwnPropertySymbols(target)); + }; +} else { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target); + }; +} + +function ProcessEmitWarning(warning) { + if (console && console.warn) console.warn(warning); +} + +var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { + return value !== value; +} + +function EventEmitter() { + EventEmitter.init.call(this); +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (EventEmitter); + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._eventsCount = 0; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +var defaultMaxListeners = 10; + +function checkListener(listener) { + if (typeof listener !== 'function') { + throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); + } +} + +Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { + throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); + } + defaultMaxListeners = arg; + } +}); + +EventEmitter.init = function() { + + if (this._events === undefined || + this._events === Object.getPrototypeOf(this)._events) { + this._events = Object.create(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; +}; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { + throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); + } + this._maxListeners = n; + return this; +}; + +function _getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; +} + +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return _getMaxListeners(this); +}; + +EventEmitter.prototype.emit = function emit(type) { + var args = []; + for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); + var doError = (type === 'error'); + + var events = this._events; + if (events !== undefined) + doError = (doError && events.error === undefined); + else if (!doError) + return false; + + // If there is no 'error' event listener then throw. + if (doError) { + var er; + if (args.length > 0) + er = args[0]; + if (er instanceof Error) { + // Note: The comments on the `throw` lines are intentional, they show + // up in Node's output if this results in an unhandled exception. + throw er; // Unhandled 'error' event + } + // At least give some kind of context to the user + var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); + err.context = er; + throw err; // Unhandled 'error' event + } + + var handler = events[type]; + + if (handler === undefined) + return false; + + if (typeof handler === 'function') { + ReflectApply(handler, this, args); + } else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + ReflectApply(listeners[i], this, args); + } + + return true; +}; + +function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + checkListener(listener); + + events = target._events; + if (events === undefined) { + events = target._events = Object.create(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener !== undefined) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } + + if (existing === undefined) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; + // If we've already got an array, just append. + } else if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + + // Check for listener leak + m = _getMaxListeners(target); + if (m > 0 && existing.length > m && !existing.warned) { + existing.warned = true; + // No error code for this since it is a Warning + // eslint-disable-next-line no-restricted-syntax + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' ' + String(type) + ' listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + ProcessEmitWarning(w); + } + } + + return target; +} + +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; + +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + if (arguments.length === 0) + return this.listener.call(this.target); + return this.listener.apply(this.target, arguments); + } +} + +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = onceWrapper.bind(state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} + +EventEmitter.prototype.once = function once(type, listener) { + checkListener(listener); + this.on(type, _onceWrap(this, type, listener)); + return this; +}; + +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + checkListener(listener); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; + + checkListener(listener); + + events = this._events; + if (events === undefined) + return this; + + list = events[type]; + if (list === undefined) + return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); + else { + spliceOne(list, position); + } + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener !== undefined) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (events === undefined) + return this; + + // not listening for removeListener, no need to emit + if (events.removeListener === undefined) { + if (arguments.length === 0) { + this._events = Object.create(null); + this._eventsCount = 0; + } else if (events[type] !== undefined) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else + delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = Object.keys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = Object.create(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners !== undefined) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; + +function _listeners(target, type, unwrap) { + var events = target._events; + + if (events === undefined) + return []; + + var evlistener = events[type]; + if (evlistener === undefined) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? + unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); +} + +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); +}; + +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); +}; + +EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } +}; + +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events !== undefined) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener !== undefined) { + return evlistener.length; + } + } + + return 0; +} + +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; +}; + +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; +} + +function spliceOne(list, index) { + for (; index + 1 < list.length; index++) + list[index] = list[index + 1]; + list.pop(); +} + +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} + +function once(emitter, name) { + return new Promise(function (resolve, reject) { + function errorListener(err) { + emitter.removeListener(name, resolver); + reject(err); + } + + function resolver() { + if (typeof emitter.removeListener === 'function') { + emitter.removeListener('error', errorListener); + } + resolve([].slice.call(arguments)); + }; + + eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); + if (name !== 'error') { + addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); + } + }); +} + +function addErrorHandlerIfEventEmitter(emitter, handler, flags) { + if (typeof emitter.on === 'function') { + eventTargetAgnosticAddListener(emitter, 'error', handler, flags); + } +} + +function eventTargetAgnosticAddListener(emitter, name, listener, flags) { + if (typeof emitter.on === 'function') { + if (flags.once) { + emitter.once(name, listener); + } else { + emitter.on(name, listener); + } + } else if (typeof emitter.addEventListener === 'function') { + // EventTarget does not have `error` event semantics like Node + // EventEmitters, we do not listen for `error` events here. + emitter.addEventListener(name, function wrapListener(arg) { + // IE does not have builtin `{ once: true }` support so we + // have to do it manually. + if (flags.once) { + emitter.removeEventListener(name, wrapListener); + } + listener(arg); + }); + } else { + throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); + } +} + +/***/ }), +/* 3 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + + +const Parser = __webpack_require__(4); +const Serializer = __webpack_require__(26); + +// Shorthands +exports.parse = function parse(html, options) { + const parser = new Parser(options); + + return parser.parse(html); +}; + +exports.parseFragment = function parseFragment(fragmentContext, html, options) { + if (typeof fragmentContext === 'string') { + options = html; + html = fragmentContext; + fragmentContext = null; + } + + const parser = new Parser(options); + + return parser.parseFragment(html, fragmentContext); +}; + +exports.serialize = function(node, options) { + const serializer = new Serializer(node, options); + + return serializer.serialize(); +}; + + +/***/ }), +/* 4 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +const Tokenizer = __webpack_require__(5); +const OpenElementStack = __webpack_require__(10); +const FormattingElementList = __webpack_require__(12); +const LocationInfoParserMixin = __webpack_require__(13); +const ErrorReportingParserMixin = __webpack_require__(18); +const Mixin = __webpack_require__(14); +const defaultTreeAdapter = __webpack_require__(22); +const mergeOptions = __webpack_require__(23); +const doctype = __webpack_require__(24); +const foreignContent = __webpack_require__(25); +const ERR = __webpack_require__(8); +const unicode = __webpack_require__(7); +const HTML = __webpack_require__(11); + +//Aliases +const $ = HTML.TAG_NAMES; +const NS = HTML.NAMESPACES; +const ATTRS = HTML.ATTRS; + +const DEFAULT_OPTIONS = { + scriptingEnabled: true, + sourceCodeLocationInfo: false, + onParseError: null, + treeAdapter: defaultTreeAdapter +}; + +//Misc constants +const HIDDEN_INPUT_TYPE = 'hidden'; + +//Adoption agency loops iteration count +const AA_OUTER_LOOP_ITER = 8; +const AA_INNER_LOOP_ITER = 3; + +//Insertion modes +const INITIAL_MODE = 'INITIAL_MODE'; +const BEFORE_HTML_MODE = 'BEFORE_HTML_MODE'; +const BEFORE_HEAD_MODE = 'BEFORE_HEAD_MODE'; +const IN_HEAD_MODE = 'IN_HEAD_MODE'; +const IN_HEAD_NO_SCRIPT_MODE = 'IN_HEAD_NO_SCRIPT_MODE'; +const AFTER_HEAD_MODE = 'AFTER_HEAD_MODE'; +const IN_BODY_MODE = 'IN_BODY_MODE'; +const TEXT_MODE = 'TEXT_MODE'; +const IN_TABLE_MODE = 'IN_TABLE_MODE'; +const IN_TABLE_TEXT_MODE = 'IN_TABLE_TEXT_MODE'; +const IN_CAPTION_MODE = 'IN_CAPTION_MODE'; +const IN_COLUMN_GROUP_MODE = 'IN_COLUMN_GROUP_MODE'; +const IN_TABLE_BODY_MODE = 'IN_TABLE_BODY_MODE'; +const IN_ROW_MODE = 'IN_ROW_MODE'; +const IN_CELL_MODE = 'IN_CELL_MODE'; +const IN_SELECT_MODE = 'IN_SELECT_MODE'; +const IN_SELECT_IN_TABLE_MODE = 'IN_SELECT_IN_TABLE_MODE'; +const IN_TEMPLATE_MODE = 'IN_TEMPLATE_MODE'; +const AFTER_BODY_MODE = 'AFTER_BODY_MODE'; +const IN_FRAMESET_MODE = 'IN_FRAMESET_MODE'; +const AFTER_FRAMESET_MODE = 'AFTER_FRAMESET_MODE'; +const AFTER_AFTER_BODY_MODE = 'AFTER_AFTER_BODY_MODE'; +const AFTER_AFTER_FRAMESET_MODE = 'AFTER_AFTER_FRAMESET_MODE'; + +//Insertion mode reset map +const INSERTION_MODE_RESET_MAP = { + [$.TR]: IN_ROW_MODE, + [$.TBODY]: IN_TABLE_BODY_MODE, + [$.THEAD]: IN_TABLE_BODY_MODE, + [$.TFOOT]: IN_TABLE_BODY_MODE, + [$.CAPTION]: IN_CAPTION_MODE, + [$.COLGROUP]: IN_COLUMN_GROUP_MODE, + [$.TABLE]: IN_TABLE_MODE, + [$.BODY]: IN_BODY_MODE, + [$.FRAMESET]: IN_FRAMESET_MODE +}; + +//Template insertion mode switch map +const TEMPLATE_INSERTION_MODE_SWITCH_MAP = { + [$.CAPTION]: IN_TABLE_MODE, + [$.COLGROUP]: IN_TABLE_MODE, + [$.TBODY]: IN_TABLE_MODE, + [$.TFOOT]: IN_TABLE_MODE, + [$.THEAD]: IN_TABLE_MODE, + [$.COL]: IN_COLUMN_GROUP_MODE, + [$.TR]: IN_TABLE_BODY_MODE, + [$.TD]: IN_ROW_MODE, + [$.TH]: IN_ROW_MODE +}; + +//Token handlers map for insertion modes +const TOKEN_HANDLERS = { + [INITIAL_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: tokenInInitialMode, + [Tokenizer.NULL_CHARACTER_TOKEN]: tokenInInitialMode, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: doctypeInInitialMode, + [Tokenizer.START_TAG_TOKEN]: tokenInInitialMode, + [Tokenizer.END_TAG_TOKEN]: tokenInInitialMode, + [Tokenizer.EOF_TOKEN]: tokenInInitialMode + }, + [BEFORE_HTML_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: tokenBeforeHtml, + [Tokenizer.NULL_CHARACTER_TOKEN]: tokenBeforeHtml, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagBeforeHtml, + [Tokenizer.END_TAG_TOKEN]: endTagBeforeHtml, + [Tokenizer.EOF_TOKEN]: tokenBeforeHtml + }, + [BEFORE_HEAD_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: tokenBeforeHead, + [Tokenizer.NULL_CHARACTER_TOKEN]: tokenBeforeHead, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: misplacedDoctype, + [Tokenizer.START_TAG_TOKEN]: startTagBeforeHead, + [Tokenizer.END_TAG_TOKEN]: endTagBeforeHead, + [Tokenizer.EOF_TOKEN]: tokenBeforeHead + }, + [IN_HEAD_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: tokenInHead, + [Tokenizer.NULL_CHARACTER_TOKEN]: tokenInHead, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: misplacedDoctype, + [Tokenizer.START_TAG_TOKEN]: startTagInHead, + [Tokenizer.END_TAG_TOKEN]: endTagInHead, + [Tokenizer.EOF_TOKEN]: tokenInHead + }, + [IN_HEAD_NO_SCRIPT_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: tokenInHeadNoScript, + [Tokenizer.NULL_CHARACTER_TOKEN]: tokenInHeadNoScript, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: misplacedDoctype, + [Tokenizer.START_TAG_TOKEN]: startTagInHeadNoScript, + [Tokenizer.END_TAG_TOKEN]: endTagInHeadNoScript, + [Tokenizer.EOF_TOKEN]: tokenInHeadNoScript + }, + [AFTER_HEAD_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: tokenAfterHead, + [Tokenizer.NULL_CHARACTER_TOKEN]: tokenAfterHead, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: misplacedDoctype, + [Tokenizer.START_TAG_TOKEN]: startTagAfterHead, + [Tokenizer.END_TAG_TOKEN]: endTagAfterHead, + [Tokenizer.EOF_TOKEN]: tokenAfterHead + }, + [IN_BODY_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: characterInBody, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: whitespaceCharacterInBody, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInBody, + [Tokenizer.END_TAG_TOKEN]: endTagInBody, + [Tokenizer.EOF_TOKEN]: eofInBody + }, + [TEXT_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.NULL_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.COMMENT_TOKEN]: ignoreToken, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: ignoreToken, + [Tokenizer.END_TAG_TOKEN]: endTagInText, + [Tokenizer.EOF_TOKEN]: eofInText + }, + [IN_TABLE_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: characterInTable, + [Tokenizer.NULL_CHARACTER_TOKEN]: characterInTable, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: characterInTable, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInTable, + [Tokenizer.END_TAG_TOKEN]: endTagInTable, + [Tokenizer.EOF_TOKEN]: eofInBody + }, + [IN_TABLE_TEXT_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: characterInTableText, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: whitespaceCharacterInTableText, + [Tokenizer.COMMENT_TOKEN]: tokenInTableText, + [Tokenizer.DOCTYPE_TOKEN]: tokenInTableText, + [Tokenizer.START_TAG_TOKEN]: tokenInTableText, + [Tokenizer.END_TAG_TOKEN]: tokenInTableText, + [Tokenizer.EOF_TOKEN]: tokenInTableText + }, + [IN_CAPTION_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: characterInBody, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: whitespaceCharacterInBody, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInCaption, + [Tokenizer.END_TAG_TOKEN]: endTagInCaption, + [Tokenizer.EOF_TOKEN]: eofInBody + }, + [IN_COLUMN_GROUP_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: tokenInColumnGroup, + [Tokenizer.NULL_CHARACTER_TOKEN]: tokenInColumnGroup, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInColumnGroup, + [Tokenizer.END_TAG_TOKEN]: endTagInColumnGroup, + [Tokenizer.EOF_TOKEN]: eofInBody + }, + [IN_TABLE_BODY_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: characterInTable, + [Tokenizer.NULL_CHARACTER_TOKEN]: characterInTable, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: characterInTable, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInTableBody, + [Tokenizer.END_TAG_TOKEN]: endTagInTableBody, + [Tokenizer.EOF_TOKEN]: eofInBody + }, + [IN_ROW_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: characterInTable, + [Tokenizer.NULL_CHARACTER_TOKEN]: characterInTable, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: characterInTable, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInRow, + [Tokenizer.END_TAG_TOKEN]: endTagInRow, + [Tokenizer.EOF_TOKEN]: eofInBody + }, + [IN_CELL_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: characterInBody, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: whitespaceCharacterInBody, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInCell, + [Tokenizer.END_TAG_TOKEN]: endTagInCell, + [Tokenizer.EOF_TOKEN]: eofInBody + }, + [IN_SELECT_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInSelect, + [Tokenizer.END_TAG_TOKEN]: endTagInSelect, + [Tokenizer.EOF_TOKEN]: eofInBody + }, + [IN_SELECT_IN_TABLE_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInSelectInTable, + [Tokenizer.END_TAG_TOKEN]: endTagInSelectInTable, + [Tokenizer.EOF_TOKEN]: eofInBody + }, + [IN_TEMPLATE_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: characterInBody, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: whitespaceCharacterInBody, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInTemplate, + [Tokenizer.END_TAG_TOKEN]: endTagInTemplate, + [Tokenizer.EOF_TOKEN]: eofInTemplate + }, + [AFTER_BODY_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: tokenAfterBody, + [Tokenizer.NULL_CHARACTER_TOKEN]: tokenAfterBody, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: whitespaceCharacterInBody, + [Tokenizer.COMMENT_TOKEN]: appendCommentToRootHtmlElement, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagAfterBody, + [Tokenizer.END_TAG_TOKEN]: endTagAfterBody, + [Tokenizer.EOF_TOKEN]: stopParsing + }, + [IN_FRAMESET_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagInFrameset, + [Tokenizer.END_TAG_TOKEN]: endTagInFrameset, + [Tokenizer.EOF_TOKEN]: stopParsing + }, + [AFTER_FRAMESET_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: insertCharacters, + [Tokenizer.COMMENT_TOKEN]: appendComment, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagAfterFrameset, + [Tokenizer.END_TAG_TOKEN]: endTagAfterFrameset, + [Tokenizer.EOF_TOKEN]: stopParsing + }, + [AFTER_AFTER_BODY_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: tokenAfterAfterBody, + [Tokenizer.NULL_CHARACTER_TOKEN]: tokenAfterAfterBody, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: whitespaceCharacterInBody, + [Tokenizer.COMMENT_TOKEN]: appendCommentToDocument, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagAfterAfterBody, + [Tokenizer.END_TAG_TOKEN]: tokenAfterAfterBody, + [Tokenizer.EOF_TOKEN]: stopParsing + }, + [AFTER_AFTER_FRAMESET_MODE]: { + [Tokenizer.CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.NULL_CHARACTER_TOKEN]: ignoreToken, + [Tokenizer.WHITESPACE_CHARACTER_TOKEN]: whitespaceCharacterInBody, + [Tokenizer.COMMENT_TOKEN]: appendCommentToDocument, + [Tokenizer.DOCTYPE_TOKEN]: ignoreToken, + [Tokenizer.START_TAG_TOKEN]: startTagAfterAfterFrameset, + [Tokenizer.END_TAG_TOKEN]: ignoreToken, + [Tokenizer.EOF_TOKEN]: stopParsing + } +}; + +//Parser +class Parser { + constructor(options) { + this.options = mergeOptions(DEFAULT_OPTIONS, options); + + this.treeAdapter = this.options.treeAdapter; + this.pendingScript = null; + + if (this.options.sourceCodeLocationInfo) { + Mixin.install(this, LocationInfoParserMixin); + } + + if (this.options.onParseError) { + Mixin.install(this, ErrorReportingParserMixin, { onParseError: this.options.onParseError }); + } + } + + // API + parse(html) { + const document = this.treeAdapter.createDocument(); + + this._bootstrap(document, null); + this.tokenizer.write(html, true); + this._runParsingLoop(null); + + return document; + } + + parseFragment(html, fragmentContext) { + //NOTE: use