Advertisement
firsttrue

Code Notion

Jan 11th, 2021 (edited)
2,875
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* CONFIGURATION STARTS HERE */
  2.  
  3.   /* Step 1: enter your domain name like fruitionsite.com */
  4.   const MY_DOMAIN = 'wiki.advanced-roleplay.com.br';
  5.  
  6.   /*
  7.    * Step 2: enter your URL slug to page ID mapping
  8.    * The key on the left is the slug (without the slash)
  9.    * The value on the right is the Notion page ID
  10.    */
  11.   const SLUG_TO_PAGE = {
  12.     '': '34e8a0135f1541b8852e15606d043f8d',
  13.     'primeiros-passos': '8b0b1184b4824c7e9514f0219c9f5013',
  14.     'veiculos': '7fdae73055324e00acd32ad6c5ad2d13',
  15.     'wphone': 'a0773d22570644a780676741669062f7'
  16.   };
  17.  
  18.   /* Step 3: enter your page title and description for SEO purposes */
  19.   const PAGE_TITLE = '';
  20.   const PAGE_DESCRIPTION = '';
  21.  
  22.   /* Step 4: enter a Google Font name, you can choose from https://fonts.google.com */
  23.   const GOOGLE_FONT = '';
  24.  
  25.   /* Step 5: enter any custom scripts you'd like */
  26.   const CUSTOM_SCRIPT = ``;
  27.  
  28.   /* CONFIGURATION ENDS HERE */
  29.  
  30. const PAGE_TO_SLUG = {};
  31. const slugs = [];
  32. const pages = [];
  33. Object.keys(SLUG_TO_PAGE).forEach(slug => {
  34.   const page = SLUG_TO_PAGE[slug];
  35.   slugs.push(slug);
  36.   pages.push(page);
  37.   PAGE_TO_SLUG[page] = slug;
  38. });
  39.  
  40. addEventListener("fetch", event => {
  41.   event.respondWith(fetchAndApply(event.request));
  42. });
  43.  
  44. function generateSitemap() {
  45.   let sitemap = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
  46.   slugs.forEach(
  47.     (slug) =>
  48.       (sitemap +=
  49.         "<url><loc>https://" + MY_DOMAIN + "/" + slug + "</loc></url>")
  50.   );
  51.   sitemap += "</urlset>";
  52.   return sitemap;
  53. }
  54.  
  55. const corsHeaders = {
  56.   "Access-Control-Allow-Origin": "*",
  57.   "Access-Control-Allow-Methods": "GET, HEAD, POST, PUT, OPTIONS",
  58.   "Access-Control-Allow-Headers": "Content-Type"
  59. };
  60.  
  61. function handleOptions(request) {
  62.   if (
  63.     request.headers.get("Origin") !== null &&
  64.     request.headers.get("Access-Control-Request-Method") !== null &&
  65.     request.headers.get("Access-Control-Request-Headers") !== null
  66.   ) {
  67.     // Handle CORS pre-flight request.
  68.     return new Response(null, {
  69.       headers: corsHeaders
  70.     });
  71.   } else {
  72.     // Handle standard OPTIONS request.
  73.     return new Response(null, {
  74.       headers: {
  75.         Allow: "GET, HEAD, POST, PUT, OPTIONS"
  76.       }
  77.     });
  78.   }
  79. }
  80.  
  81. async function fetchAndApply(request) {
  82.   if (request.method === "OPTIONS") {
  83.     return handleOptions(request);
  84.   }
  85.   let url = new URL(request.url);
  86.   url.hostname = 'www.notion.so';
  87.   if (url.pathname === "/robots.txt") {
  88.     return new Response("Sitemap: https://" + MY_DOMAIN + "/sitemap.xml");
  89.   }
  90.   if (url.pathname === "/sitemap.xml") {
  91.     let response = new Response(generateSitemap());
  92.     response.headers.set("content-type", "application/xml");
  93.     return response;
  94.   }
  95.   let response;
  96.   if (url.pathname.startsWith("/app") && url.pathname.endsWith("js")) {
  97.     response = await fetch(url.toString());
  98.     let body = await response.text();
  99.     response = new Response(
  100.       body
  101.         .replace(/www.notion.so/g, MY_DOMAIN)
  102.         .replace(/notion.so/g, MY_DOMAIN),
  103.       response
  104.     );
  105.     response.headers.set("Content-Type", "application/x-javascript");
  106.     return response;
  107.   } else if (url.pathname.startsWith("/api")) {
  108.     // Forward API
  109.     response = await fetch(url.toString(), {
  110.       body: request.body,
  111.       headers: {
  112.         "content-type": "application/json;charset=UTF-8",
  113.         "user-agent":
  114.           "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
  115.       },
  116.       method: "POST"
  117.     });
  118.     response = new Response(response.body, response);
  119.     response.headers.set("Access-Control-Allow-Origin", "*");
  120.     return response;
  121.   } else if (slugs.indexOf(url.pathname.slice(1)) > -1) {
  122.     const pageId = SLUG_TO_PAGE[url.pathname.slice(1)];
  123.     return Response.redirect("https://" + MY_DOMAIN + "/" + pageId, 301);
  124.   } else {
  125.     response = await fetch(url.toString(), {
  126.       body: request.body,
  127.       headers: request.headers,
  128.       method: request.method
  129.     });
  130.     response = new Response(response.body, response);
  131.     response.headers.delete("Content-Security-Policy");
  132.     response.headers.delete("X-Content-Security-Policy");
  133.   }
  134.  
  135.   return appendJavascript(response, SLUG_TO_PAGE);
  136. }
  137.  
  138. class MetaRewriter {
  139.   element(element) {
  140.     if (PAGE_TITLE !== "") {
  141.       if (
  142.         element.getAttribute("property") === "og:title" ||
  143.         element.getAttribute("name") === "twitter:title"
  144.       ) {
  145.         element.setAttribute("content", PAGE_TITLE);
  146.       }
  147.       if (element.tagName === "title") {
  148.         element.setInnerContent(PAGE_TITLE);
  149.       }
  150.     }
  151.     if (PAGE_DESCRIPTION !== "") {
  152.       if (
  153.         element.getAttribute("name") === "description" ||
  154.         element.getAttribute("property") === "og:description" ||
  155.         element.getAttribute("name") === "twitter:description"
  156.       ) {
  157.         element.setAttribute("content", PAGE_DESCRIPTION);
  158.       }
  159.     }
  160.     if (
  161.       element.getAttribute("property") === "og:url" ||
  162.       element.getAttribute("name") === "twitter:url"
  163.     ) {
  164.       element.setAttribute("content", MY_DOMAIN);
  165.     }
  166.     if (element.getAttribute("name") === "apple-itunes-app") {
  167.       element.remove();
  168.     }
  169.   }
  170. }
  171.  
  172. class HeadRewriter {
  173.   element(element) {
  174.     if (GOOGLE_FONT !== "") {
  175.       element.append(
  176.         `<link href='https://fonts.googleapis.com/css?family=${GOOGLE_FONT.replace(' ', '+')}:Regular,Bold,Italic&display=swap' rel='stylesheet'>
  177.         <style>* { font-family: "${GOOGLE_FONT}" !important; }</style>`,
  178.         {
  179.           html: true
  180.         }
  181.       );
  182.     }
  183.     element.append(
  184.       `<style>
  185.       div.notion-topbar > div > div:nth-child(3) { display: none !important; }
  186.       div.notion-topbar > div > div:nth-child(4) { display: none !important; }
  187.       div.notion-topbar > div > div:nth-child(5) { display: none !important; }
  188.       div.notion-topbar > div > div:nth-child(6) { display: none !important; }
  189.       div.notion-topbar-mobile > div:nth-child(3) { display: none !important; }
  190.       div.notion-topbar-mobile > div:nth-child(4) { display: none !important; }
  191.       div.notion-topbar > div > div:nth-child(1n).toggle-mode { display: block !important; }
  192.       div.notion-topbar-mobile > div:nth-child(1n).toggle-mode { display: block !important; }
  193.       </style>`,
  194.       {
  195.         html: true
  196.       }
  197.     );
  198.   }
  199. }
  200.  
  201. class BodyRewriter {
  202.   constructor(SLUG_TO_PAGE) {
  203.     this.SLUG_TO_PAGE = SLUG_TO_PAGE;
  204.   }
  205.   element(element) {
  206.     element.append(
  207.       `<script>
  208.       const SLUG_TO_PAGE = ${JSON.stringify(this.SLUG_TO_PAGE)};
  209.       const PAGE_TO_SLUG = {};
  210.       const slugs = [];
  211.       const pages = [];
  212.       const el = document.createElement('div');
  213.       let redirected = false;
  214.       Object.keys(SLUG_TO_PAGE).forEach(slug => {
  215.         const page = SLUG_TO_PAGE[slug];
  216.         slugs.push(slug);
  217.         pages.push(page);
  218.         PAGE_TO_SLUG[page] = slug;
  219.       });
  220.       function getPage() {
  221.         return location.pathname.slice(-32);
  222.       }
  223.       function getSlug() {
  224.         return location.pathname.slice(1);
  225.       }
  226.       function updateSlug() {
  227.         const slug = PAGE_TO_SLUG[getPage()];
  228.         if (slug != null) {
  229.           history.replaceState(history.state, '', '/' + slug);
  230.         }
  231.       }
  232.       function onDark() {
  233.         el.innerHTML = '<div title="Change to Light Mode" style="margin-left: auto; margin-right: 14px; min-width: 0px;"><div role="button" tabindex="0" style="user-select: none; transition: background 120ms ease-in 0s; cursor: pointer; border-radius: 44px;"><div style="display: flex; flex-shrink: 0; height: 14px; width: 26px; border-radius: 44px; padding: 2px; box-sizing: content-box; background: rgb(46, 170, 220); transition: background 200ms ease 0s, box-shadow 200ms ease 0s;"><div style="width: 14px; height: 14px; border-radius: 44px; background: white; transition: transform 200ms ease-out 0s, background 200ms ease-out 0s; transform: translateX(12px) translateY(0px);"></div></div></div></div>';
  234.         document.body.classList.add('dark');
  235.         __console.environment.ThemeStore.setState({ mode: 'dark' });
  236.       };
  237.       function onLight() {
  238.         el.innerHTML = '<div title="Change to Dark Mode" style="margin-left: auto; margin-right: 14px; min-width: 0px;"><div role="button" tabindex="0" style="user-select: none; transition: background 120ms ease-in 0s; cursor: pointer; border-radius: 44px;"><div style="display: flex; flex-shrink: 0; height: 14px; width: 26px; border-radius: 44px; padding: 2px; box-sizing: content-box; background: rgba(135, 131, 120, 0.3); transition: background 200ms ease 0s, box-shadow 200ms ease 0s;"><div style="width: 14px; height: 14px; border-radius: 44px; background: white; transition: transform 200ms ease-out 0s, background 200ms ease-out 0s; transform: translateX(0px) translateY(0px);"></div></div></div></div>';
  239.         document.body.classList.remove('dark');
  240.         __console.environment.ThemeStore.setState({ mode: 'light' });
  241.       }
  242.       function toggle() {
  243.         if (document.body.classList.contains('dark')) {
  244.           onLight();
  245.         } else {
  246.           onDark();
  247.         }
  248.       }
  249.       function addDarkModeButton(device) {
  250.         const nav = device === 'web' ? document.querySelector('.notion-topbar').firstChild : document.querySelector('.notion-topbar-mobile');
  251.         el.className = 'toggle-mode';
  252.         el.addEventListener('click', toggle);
  253.         nav.appendChild(el);
  254.         onLight();
  255.       }
  256.       const observer = new MutationObserver(function() {
  257.         if (redirected) return;
  258.         const nav = document.querySelector('.notion-topbar');
  259.         const mobileNav = document.querySelector('.notion-topbar-mobile');
  260.         if (nav && nav.firstChild && nav.firstChild.firstChild
  261.           || mobileNav && mobileNav.firstChild) {
  262.           redirected = true;
  263.           updateSlug();
  264.           addDarkModeButton(nav ? 'web' : 'mobile');
  265.           const onpopstate = window.onpopstate;
  266.           window.onpopstate = function() {
  267.             if (slugs.includes(getSlug())) {
  268.               const page = SLUG_TO_PAGE[getSlug()];
  269.               if (page) {
  270.                 history.replaceState(history.state, 'bypass', '/' + page);
  271.               }
  272.             }
  273.             onpopstate.apply(this, [].slice.call(arguments));
  274.             updateSlug();
  275.           };
  276.         }
  277.       });
  278.       observer.observe(document.querySelector('#notion-app'), {
  279.         childList: true,
  280.         subtree: true,
  281.       });
  282.       const replaceState = window.history.replaceState;
  283.       window.history.replaceState = function(state) {
  284.         if (arguments[1] !== 'bypass' && slugs.includes(getSlug())) return;
  285.         return replaceState.apply(window.history, arguments);
  286.       };
  287.       const pushState = window.history.pushState;
  288.       window.history.pushState = function(state) {
  289.         const dest = new URL(location.protocol + location.host + arguments[2]);
  290.         const id = dest.pathname.slice(-32);
  291.         if (pages.includes(id)) {
  292.           arguments[2] = '/' + PAGE_TO_SLUG[id];
  293.         }
  294.         return pushState.apply(window.history, arguments);
  295.       };
  296.       const open = window.XMLHttpRequest.prototype.open;
  297.       window.XMLHttpRequest.prototype.open = function() {
  298.         arguments[1] = arguments[1].replace('${MY_DOMAIN}', 'www.notion.so');
  299.         return open.apply(this, [].slice.call(arguments));
  300.       };
  301.     </script>${CUSTOM_SCRIPT}`,
  302.       {
  303.         html: true
  304.       }
  305.     );
  306.   }
  307. }
  308.  
  309. async function appendJavascript(res, SLUG_TO_PAGE) {
  310.   return new HTMLRewriter()
  311.     .on("title", new MetaRewriter())
  312.     .on("meta", new MetaRewriter())
  313.     .on("head", new HeadRewriter())
  314.     .on("body", new BodyRewriter(SLUG_TO_PAGE))
  315.     .transform(res);
  316. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement